Crate small_ctor

source ·
Expand description

A dependency free library that declares functions to be automatically executed before main is invoked.

This crate implements the exact same behavior as the ctor crate with the following differences:

  • It has no dependencies other than proc_macro itself.
  • It requires that functions are marked with unsafe.
  • It can only be used with functions, not static items.
  • It only supports #[ctor]

Example

This is a motivating example that registers a struct as a plugin in a hypothetical global plugins registry:

struct MyPlugin;

#[small_ctor::ctor]
unsafe fn register_plugin() {
    PLUGINS.register(MyPlugin);
}

Safety

This library involves “life before main” which is explicitly not permitted in Rust which is why this library is anything but safe. In fact, it’s a really bad idea to do what this crate is promoting. For instance at present code that runs in #[ctor] will run before lang_start managed to execute. Some of the effects of this are that the main thread does not have a name yet, the stack protection is not enabled and code must not panic.

It’s recommended that the only thing you do in a #[ctor] function is to append to a vector, insert into a hashmap or similar.

It’s recommended to perform basic operations which are unlikely to panic and to defer most work to when the actual main happens. So for instead instead of initializing plugins in the ctor, just push them to a plugin registry and then trigger callbacks registered that way regularly in main.

Compiler and Linker Bugs

Currently this library is prone to break due to compiler bugs in subtle ways. The core issue is rust #47384. You can reduze the likelihood of it happening by disabling incremental compilation or setting codegen-units to 1 in your profile in the Cargo.toml.

Destructors

This crate intentionally does not support an at-exit mechanism. The reason for this is that those are running so late that even more Rust code is unable to properly run. Not only does panicking not work, the entire standard IO system is already unusable. More importantly on many platforms these do not run properly. For instance on macOS destructors do not run when thread local storage is in use. If you do want to use something like this you can do something like invoke libc::at_exit from within a #[ctor] function.

Attribute Macros

  • Marks a function or static variable as a library/executable constructor. This uses OS-specific linker sections to call a specific function at load time.