Skip to main content

Module executor_handle

Module executor_handle 

Source
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’s executor) — an nros-cpp CppContext, which carries the executor at a NON-zero offset, behind the CPP_CONTEXT_TAG word 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).