Crate hotpatch[][src]

Changing function definitions at runtime.

This crate is primarily used to load new function definitions from shared object files in an exceedingly easy way.

Short Example

The following shows how dead-simple this crate is to use:

// main.rs
use hotpatch::*;

#[patchable]
fn foo() { }

fn main() -> Result<(), Box<dyn std::error::Error>> {
  foo(); // does nothing
  foo.hotpatch_lib("libsomething.so")?;
  foo(); // does something totally different!
  Ok(())
}

What about defining a patch? Also easy:

// lib.rs
use hotpatch::patch;

#[patch]
fn foo() { }

For more examples see the git repo.

Methods and Free Functions

hotpatch also works with methods.

Note: hotpatch currently only works with free functions (methods without a self parameter). Actual method support is in progress and expected in the next version.

Note: #[patchable] and #[patch] must be placed outside of impl bodies!

Example

Setting up is done like so:

// main.rs
use hotpatch::*;

struct Foo {}
#[patchable]
impl Foo {
    pub fn bar() {
        println!("I can be changed!");
    }
}

Patches are declared like this:

struct Foo {}

#[patch]
impl Foo {
    /// remember, #[patch] is top-level
    pub fn bar() {
        println!("this is external!");
    }
}

Finally, patching is done as so.

fn main() -> Result<(), Box<dyn std::error::Error>> {
    Foo::bar();
    Foo::bar.hotpatch_fn(|| println!("this is patch!"))?;
    Foo::bar();
    Foo::bar.hotpatch_lib("target/debug/libmethods_obj.so")?;
    Foo::bar();
    Ok(())
}

Features

For reference, this crate recognizes the following features:

  • allow-main: Allow setting main as #[patchable]. Only useful if using #[start] or #[main].
  • redirect-main: Same as allow-main but also generates a stub #[main] to call the Patchable. If you just want to hotpatch main, this is probably the right feature. Requires nightly and #[feature(main)].
  • large-signatures: Tweaks the variadic generics engine. See hotpatch_fn.

Warnings

Under normal operation, this crate provides type safety, thread safety, namepace safety, and a whole bunch of other guarantees. However, use of this crate is still playing with fire.

The one thing that cannot be checked against is call stack safety. Because Patchable uses RwLocks the current thread is blocked when trying to hotpatch a function. This ensures that an out-of-date function body cannot be run. However if the function being hotpatched is the current function or anywhere within the call stack (eg patching a function that called the current function) a deadlock will occur. Be careful!

The try methods within Patchable provide additional checks for this, but may cause other problems in multithreaded environments.

Bypassing Thread Safety

The previous section mentions being unable to hotpatch currently running functions. This is a deliberate safety feature. However, it can be bypassed by using the force methods within Patchable. This allows multiple functions definitions to run at once. This is unsafe, but allows for some really interesting things such as hotpatching main.

Structs

HotpatchExport

Created by #[patch]. Internal use only.

MutConst
Patchable

Created by #[patchable]. A functor capable of overwriting its own function.

Traits

HotpatchFn

Public interface for Patchable::hotpatch_fn and associated; requires import to use

HotpatchLib

Public interface for Patchable::hotpatch_lib and associated; requires import to use

Attribute Macros

patch

Transforms a function into a HotpatchExport capable of being exported and changing the behavior of a function in a seperate binary at runtime. The original function is preserved.

patchable

Transforms a function into a Patchable capable of having its behavior redefined at runtime.