Skip to main content

apply_patch

Function apply_patch 

Source
pub unsafe fn apply_patch(table: JumpTable) -> Result<(), PatchError>
Expand description

Apply a patch: load table.lib, rebase table’s addresses onto this process and the loaded library, install it, then run every register_handler handler.

Calls are serialised end to end: a concurrent call waits for the running one to finish, handlers included. Fails closed, before loading anything: a release-profile build (PatchError::ReleaseBuild), no anchor set with set_anchor (PatchError::AnchorUnresolved), an unlocatable base image (PatchError::ImageRangeUnresolved), or any unreported layout-mismatch record (PatchError::LayoutMismatchPending, checked under the lock, so every apply entry refuses the same way until the host calls mark_layout_mismatches_reported). The patch library must export ANCHOR_SYMBOL, else PatchError::Dlopen. On any error nothing is installed and no handler runs.

A table whose anchor addresses are not those of ANCHOR_SYMBOL is refused with PatchError::AnchorMismatch: the offset implied by aslr_reference must equal the running image’s slide, and the one implied by new_base_address the patch image’s slide. The base check runs before the library is loaded; a patch-side refusal leaves the library mapped and leaked.

§Safety

This detours live functions to code from another binary. A malformed or mismatched table (one not built against this exact executable) makes calls jump to arbitrary addresses with the wrong signatures. Only apply tables produced by the patch builder for this running build.

Two anchor preconditions hold the rebase honest. Both are checked at run time (PatchError::AnchorMismatch) but stated here because a table is trusted input: table.aslr_reference must be the link-time address of __frust_hotpatch_anchor in the running base image, and table.new_base_address its link-time address in the patch library. A table anchored on any other symbol (for example main, as dx 0.7.10 builds it) is not valid.

A well-formed table built against this executable is not enough on its own. Entries are matched by symbol name, and a name does not encode layout, so the caller must also ensure that every mapped function’s argument, return and capture types keep their layout between the running image and the patch: every type whose values cross images keeps its layout. Otherwise the patched function reads and writes live values through the new layout: the measured case is a component’s build taking (&C, &mut C::State) after a field grew C::State from 4 to 8 bytes (the hot-patch spike’s RESULTS.md, row D2). Closures dispatched through HotFn::current carry their captures as an argument, so a changed capture is the same hazard. Checking this is the patch builder’s job (its L3 gate, the spike’s PORT.md section 2(c)); this function cannot see layouts.

Refuses with PatchError::LayoutMismatchPending while any layout-mismatch record is unreported (report_layout_mismatch); the caller must report the records to the host and call mark_layout_mismatches_reported before a patch can apply.

It loads a library and allocates, so it must not run where the process is stopped (e.g. in a signal handler), nor from a patch handler (it would wait on its own lock).