Skip to content

fix(serialization): contain fastcdr/std exceptions in serialize() [P1] - #4

Merged
benaliabderrahmane merged 1 commit into
mainfrom
fix/p1-1-serialize-exception-boundary
Jun 5, 2026
Merged

benaliabderrahmane merged 1 commit into
mainfrom
fix/p1-1-serialize-exception-boundary

Conversation

@benaliabderrahmane

Copy link
Copy Markdown
Owner

Severity: P1 — found by a full multi-agent code audit of rmw_unix_socket_cpp (method + findings in AUDIT_FINAL.md).

Problem

serialize() had no exception guard, while its sibling deserialize() wraps its fastcdr calls in try/catch. In serialize():

  • callbacks->get_serialized_size() can throw std::overflow_error (bounded sequence / string overflow);
  • ser.serialize_encapsulation() / callbacks->cdr_serialize() can throw eprosima::fastcdr::exception::Exception (e.g. BadParamException on a std::string field carrying an embedded \0).

Every caller is extern "C" (rmw_publish, rmw_serialize, rmw_send_request, rmw_send_response), so a thrown exception unwinds across the C ABI into rcl → std::terminate() (process abort).

Fix

Wrap the body of serialize() and return false on failure, mirroring deserialize():

  • catch (const eprosima::fastcdr::exception::Exception &) — fastcdr's Exception does not derive from std::exception, so it needs its own clause;
  • catch (const std::exception &) — covers get_serialized_size()'s std::overflow_error and buffer.resize()'s std::bad_alloc.

All callers already do if (!serialize(...)) return RMW_RET_ERROR;.

File: rmw_unix_socket_cpp/src/serialization.cpp
Build: clean colcon build (library), 0 warnings.

@benaliabderrahmane

Copy link
Copy Markdown
Owner Author

Reviewed the diff, surrounding context, and CI. This is a correct, focused, portable P1 fix — recommend merge after a one-line PR-body correction; the negative test is a nice-to-have, not a blocker.

What I checked:

  • The fix wraps the body of serialize() in try/catch returning false (serialization.cpp:101-128), mirroring the existing deserialize() sibling (lines 144-156). fastcdr/std exceptions from get_serialized_size(), serialize_encapsulation(), cdr_serialize(), and buffer.resize() can no longer unwind across the extern "C" ABI into std::terminate().
  • All callers already gate on the bool return (if (!serialize(...)) return RMW_RET_ERROR;), so returning false is handled.
  • Catch-clause ordering is correct and portable: the fastcdr clause precedes the std::exception clause. On jazzy Exception derives from std::exception (Exception.h:29), so derived-first matching matters and is satisfied; on kilted/rolling Exception has no base, so the dedicated clause is required. CI green on all three distros.
  • No new allocation/concurrency/lifetime hazards: resize-then-trim semantics are unchanged and FastBuffer/Cdr are stack-local.

Non-blocking:

  1. Doc nit — the body's rationale for the dedicated fastcdr catch is version-inverted. It says fastcdr's Exception "does not derive from std::exception, so it needs its own clause." That's true on kilted/rolling but false on jazzy (Exception.h:29 = class Exception : public std::exception). The code is correct everywhere thanks to the derived-first ordering — only the prose is wrong. Worth fixing so a future reader doesn't delete the "redundant" clause and break kilted/rolling.
  2. Test nit (CLAUDE.md §4) — no failing-test-first regression test for the escape path. test_serialization.cpp is untouched (only happy-path ASSERT_TRUE cases). A repro is cheap: test_msgs Strings.msg has string<=22 bounded_string_value, so a >22-char assignment exercises the bounded-string overflow the new catch contains, and the test target is already wired (CMakeLists.txt:146-148). Not blocking since the fix is correct, CI is green, and deserialize() already ships the same untested pattern in main — but a negative test would lock in the behavior.

@benaliabderrahmane
benaliabderrahmane merged commit 2a77e9d into main Jun 5, 2026
3 checks passed
@benaliabderrahmane
benaliabderrahmane deleted the fix/p1-1-serialize-exception-boundary branch June 17, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant