Skip to main content

Crate frust_hotpatch

Crate frust_hotpatch 

Source
Expand description

Frust’s native-only hot-patch runtime: the in-app half of hot patching.

Wrap a patch point in HotFn (or the free call). In a debug build every call does one lookup in the installed JumpTable, keyed on the address of the function’s HotFunction::call_it monomorphisation (or, for HotFn::from_fn_ptr, the pointer’s own value), and jumps to the patched version when one is mapped, else runs the original. There is no stale-call detection and no retry. A patch builder (today dx 0.7.10, whose wire format JumpTable matches, but whose tables are anchored on main, which apply_patch refuses with PatchError::AnchorMismatch: a table must be anchored on ANCHOR_SYMBOL) compiles the changed code into a library and sends the table; apply_patch loads that library, rebases the table onto this process, publishes it, and runs every register_handler handler. Patches are serialised, and a patch is refused before anything is loaded in a release build, while no anchor is set (set_anchor; the app defines the ANCHOR_SYMBOL function), and, in every apply entry (apply_patch and apply_from_devtools), while a layout-mismatch record is unreported (report_layout_mismatch; checked under the apply lock, PatchError::LayoutMismatchPending).

The layout precondition: every type whose values cross images (a mapped function’s arguments, return and closure captures, a component’s state) must keep its layout between the running image and a patch. Symbol names do not encode layout, so nothing here can check it; the patch builder’s L3 gate does, and the runtime reports a disagreement it meets anyway.

The patch boundary: nothing rewrites process memory, so the table only redirects calls that enter through a HotFn. Patch code is also reached without one, though: a trait object, stored closure or fn pointer created while patched code ran points straight into the patch library, and calling it later runs that code with no HotFn in between (including after a newer patch). Likewise such values created before a patch keep running the old code until they are rebuilt.

Lookups happen only under cfg!(debug_assertions). In a release build every HotFn call is a direct call and the table is never read. See the crate README for scope and differences.

Structs§

AddressHasher
Identity hasher for integer keys; AddressMap only ever feeds it a u64.
ApplyReport
What apply_from_devtools did: whether the patch was applied, and why not when it was not.
HotFn
A hot-reloadable function: HotFn::call runs the newest version the jump table maps.
HotFnPtr
The address a hot function currently resolves to.
JumpTable
One patch: the library holding the new code and the old -> new address map into it.
LayoutMismatch
A layout disagreement found at run time: a value built by one image was reached by another whose own layout for type_name differs.
MissedKey
A jump-table key that missed, located in the image the calling code belongs to.

Enums§

PatchError
Why a patch could not be applied. On every error nothing is installed and no handler runs.

Constants§

ANCHOR_SYMBOL
The symbol every patch library exports and the app defines: #[unsafe(no_mangle)] pub extern "C" fn __frust_hotpatch_anchor() {}.
UNKNOWN_IMAGE
The image index reported for an address that lies in no image this crate knows.

Traits§

FnPointer
A plain, non-higher-ranked function-pointer type fn(A, ..) -> R of up to nine arguments: the only types HotFn::from_fn_ptr accepts. Sealed; implemented by this crate only.
HotFunction
A function that can be detoured through the jump table: implemented for every FnMut of up to nine arguments (taken as a tuple). FnOnce is excluded because a patch may re-run the function.

Functions§

apply_from_devtools
The safe devtools entry: apply the patch library at bytes_path with table.
apply_patch⚠
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.
call
Call f once through the jump table.
fall_through_count
How many HotFn calls, on any thread, missed the jump table since the last patch was applied (see last_call_fell_through). Reset to zero by every successful apply_patch.
get_jump_table⚠
The installed jump table, or None before the first patch.
last_call_fell_through
Whether this thread’s most recent HotFn call found a jump table installed but no mapping for its own key, and so ran the function compiled into the calling image.
load_patch_library⚠
Load path with the platform loader apply_patch uses: dlopen/LoadLibrary through libloading on desktop, the memfd + android_dlopen_ext path on Android (which lets a library outside the app’s native-library directory load on a non-rooted device).
mark_layout_mismatches_reported
Mark reported as carried by a PatchOutcome or hotpatch_info answer. Only the records given are removed, so one reported after the caller read the list stays pending.
missed_keys
Every distinct key that missed the jump table since the last patch was applied, each once, ordered by image then link address. Reset by every patch.
pending_layout_mismatches
The layout-mismatch records not yet reported, oldest first (for hotpatch_info).
register_handler
Register handler to run right after each patch library is loaded and its jump table installed.
report_layout_mismatch
Record that type_name has layout stored in the image that created a value and own in the image now handling it. The record is kept until it is reported to the host: it is returned by pending_layout_mismatches and cleared by mark_layout_mismatches_reported. Identical records collapse into one. While any record is unreported, every apply entry (apply_patch, apply_from_devtools) refuses.
seam_hits
How many HotFn calls, on any thread, found their key in the installed jump table (and so ran the patched version) since the last patch was applied. Reset to zero by every patch.
set_anchor
Register the running executable’s anchor: the address of its __frust_hotpatch_anchor function, taken as a function pointer (__frust_hotpatch_anchor as usize).

Type Aliases§

AddressMap
An address -> address map that does not hash its keys: addresses are already unique.
BuildAddressHasher
The AddressMap hasher builder.