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).