hotpatch-rs
Live code hot reloading for Rust processes with atomic function pointer swapping and a stable C ABI contract.
What this crate provides
- Function-level patch points via symbol indirection slots.
- Runtime loading of
.so/.dllpatch modules vialibloading. - Atomic implementation swaps per symbol (
AtomicUsizepointer exchange). - State preservation by keeping application state in host process memory.
- Versioned ABI (
HOTPATCH_MODULE_V1manifest with magic + version checks). - Linux-first flow with dynamic
.somodules.
Core architecture
- Host process owns state and a
HotpatchRuntime. - Runtime keeps symbol slots that call through function pointers.
- Patch modules export
HOTPATCH_MODULE_V1describing symbol -> function mappings. - On load, runtime validates ABI, then atomically swaps slots to new implementations.
- Loaded libraries stay resident for process lifetime to avoid stale function-pointer unload hazards.
ABI surface
PatchFn signature:
unsafe extern "C" fn
This keeps host/plugin coupling explicit and stable across crate versions.
Quick usage
use HotpatchRuntime;
let runtime = new;
// runtime.register_fallback("counter.add", fallback_fn)?;
// runtime.load_module("./libcounter_patch_v2.so")?;
Demo (Linux)
The demo/ directory contains:
shared-abi: shared#[repr(C)]input/output/state structs.counter-host: long-running host process.counter-patch-v1: first patch module.counter-patch-v2: replacement patch module.
Build demo patches and host:
&&
&&
&&
The host starts with fallback behavior, loads v1, then hot-swaps to v2 without restart.
Safety notes
- Plugin function pointers are
unsafe extern "C"; host must pass valid pointers. - Struct layouts crossing ABI boundary should be
#[repr(C)]and versioned. - This crate does not yet provide quiescent-state synchronization for module unload; modules remain loaded by design.
- Optional
wasm-sandboxfeature is reserved for future pluggable execution backends.