noib3 | Hi everyone, I'm trying to write a simple Nix plugin in Rust that adds a builtins.mylib primop with a single add function, but it immediately segfaults when I call nix_alloc_value. This is the current code:
const NO_ARGS: &[*const c_char; 1] = &[ptr::null_mut()];
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn add(
_user_data: *mut c_void,
ctx: *mut nix_c_context,
_state: *mut EvalState,
args: *mut *mut Value,
ret: *mut Value,
) {
let a = nix_get_int(ctx, *args.offset(0));
let b = nix_get_int(ctx, *args.offset(1));
nix_init_int(ctx, ret, a + b);
}
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn my_lib(
_user_data: *mut c_void,
ctx: *mut nix_c_context,
state: *mut EvalState,
_args: *mut *mut Value,
ret: *mut Value,
) {
// Create an attrset builder with a capacity of 1.
let builder = nix_make_bindings_builder(ctx, state, 1);
let add_name = c"add".as_ptr();
let mut add_args: [*const c_char; 3] =
[c"a".as_ptr(), c"b".as_ptr(), ptr::null()];
let add_primop = nix_alloc_primop(
ctx,
Some(add),
2,
add_name,
add_args.as_mut_ptr(),
c"Add two integers together".as_ptr(),
ptr::null_mut(),
);
// Convert the primop into a Value and add it to the builder.
let add_value = nix_alloc_value(ctx, state);
nix_init_primop(ctx, add_value, add_primop);
nix_bindings_builder_insert(ctx, builder, add_name, add_value);
// Finalize the builder.
nix_make_attrs(ctx, ret, builder);
// Clean up.
nix_bindings_builder_free(builder);
nix_value_decref(ctx, add_value);
nix_gc_decref(ctx, add_primop as *const c_void);
}
#[unsafe(no_mangle)]
#[allow(clippy::missing_safety_doc)]
#[allow(unsafe_op_in_unsafe_fn)]
pub unsafe extern "C" fn nix_plugin_entry() {
let ctx = nix_c_context_create();
let primop = nix_alloc_primop(
ctx,
Some(my_lib),
0,
c"mylib".as_ptr(),
NO_ARGS as *const _ as *mut _,
c"mylib".as_ptr(),
ptr::null_mut(),
);
nix_register_primop(ctx, primop);
nix_gc_decref(ctx, primop as *const c_void);
nix_c_context_free(ctx);
}
Which results in:
$ nix --plugin-files ./target/debug/libnix_jettison.dylib repl
Nix 2.32.3
Type :? for help.
nix-repl> builtins.mylib
fish: Job 1, '/nix/store/0r71b4nz6rizb9l0fxdl…' terminated by signal SIGSEGV (Address boundary error)
| 13:33:49 |