Expand description
Issue 1535 — what a void* executor handle crossing the language seam is,
and the one check every seam in this crate makes before treating it as an
Executor (a C/C++ entry’s handle is an nros-cpp context, not one).
Issue 1535 — what a void* executor handed across the language seam IS.
Two different objects travel as void* and are both called “the executor
handle”:
- a Rust entry’s
RuntimeCtx::executor_handle()— a bare*mut Executor<'static>; - a C/C++ entry’s
rclcpp::global_handle()(and every tier’sexecutor) — an nros-cppCppContext, which carries the executor at a NON-zero offset, behind theCPP_CONTEXT_TAGword at offset 0.
nros-cpp’s own entry points tell them apart by that tag (issue 0436). The
seams in THIS crate that take a handle — the cross-language component
install __nros_component_<pkg>_install and the contract-monitor install —
used to cast whatever arrived straight to *mut Executor<'static>, so a
C/C++ entry installing a Rust node handed the node a pointer that was off by
the tag. Whether that crashed depended on where rustc happened to put the
fields of a repr(Rust) CppContext: the mixed Zephyr image SEGVed on its
first publish while every layout that put the executor first ran by luck.
One answer now, two halves: nros-cpp pins the tag at offset 0 (repr(C))
and exports nros_cpp_executor_inner, which the generated C++ entry calls
before it reaches a Rust install; and executor_from_handle here REFUSES a
handle that is still tagged, so a caller that forgets is a clean error
rather than a corrupted executor.
Constants§
- CPP_
CONTEXT_ TAG - The word nros-cpp stamps at offset 0 of a live
CppContext(issue 0436).