diff --git a/rust/nix-expr/src/eval_state.rs b/rust/nix-expr/src/eval_state.rs index 854cb65..b473629 100644 --- a/rust/nix-expr/src/eval_state.rs +++ b/rust/nix-expr/src/eval_state.rs @@ -8,10 +8,9 @@ use nix_store::store::Store; use nix_util::context::Context; use nix_util::result_string_init; use nix_util::string_return::{callback_get_result_string, callback_get_result_string_data}; -use std::ffi::CString; +use std::ffi::{c_char, CString}; use std::os::raw::c_uint; -use std::ptr::null_mut; -use std::ptr::NonNull; +use std::ptr::{null, null_mut, NonNull}; lazy_static! { static ref INIT: Result<()> = { @@ -48,18 +47,31 @@ pub struct EvalState { context: Context, } impl EvalState { - pub fn new(store: Store) -> Result { + pub fn new<'a>(store: Store, lookup_path: impl IntoIterator) -> Result { let context = Context::new(); + // this intermediate value must be here and must not be moved + // because it owns the data the `*const c_char` pointers point to. + let lookup_path: Vec = lookup_path + .into_iter() + .map(|path| { + CString::new(path).with_context(|| { + format!("EvalState::new: lookup_path `{path}` contains null byte") + }) + }) + .collect::>()?; + + // this intermediate value owns the data the `*mut *const c_char` pointer points to. + let mut lookup_path: Vec<*const c_char> = lookup_path + .iter() + .map(|s| s.as_ptr()) + .chain(std::iter::once(null())) // signal the end of the array + .collect(); + init()?; - let eval_state = unsafe { - raw::state_create( - context.ptr(), - /* searchPath */ null_mut(), - store.raw_ptr(), - ) - }; + let eval_state = + unsafe { raw::state_create(context.ptr(), lookup_path.as_mut_ptr(), store.raw_ptr()) }; context.check_err()?; if eval_state.is_null() { panic!("nix_state_create returned a null pointer without an error"); @@ -386,7 +398,7 @@ mod tests { gc_registering_current_thread(|| { // very basic test: make sure initialization doesn't crash let store = Store::open("auto").unwrap(); - let _e = EvalState::new(store).unwrap(); + let _e = EvalState::new(store, []).unwrap(); }) .unwrap(); } @@ -395,7 +407,7 @@ mod tests { fn eval_state_eval_from_string() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("1", "").unwrap(); let v2 = v.clone(); es.force(&v).unwrap(); @@ -412,7 +424,7 @@ mod tests { fn eval_state_value_bool() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("true", "").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -425,7 +437,7 @@ mod tests { fn eval_state_value_int() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("1", "").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -440,7 +452,7 @@ mod tests { fn eval_state_value_attrs_names_empty() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("{ }", "").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -455,7 +467,7 @@ mod tests { fn eval_state_require_attrs_names_bad_type() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("1", "").unwrap(); es.force(&v).unwrap(); let r = es.require_attrs_names(&v); @@ -472,7 +484,7 @@ mod tests { fn eval_state_value_attrs_names_example() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let expr = r#"{ a = throw "nope a"; b = throw "nope b"; }"#; let v = es.eval_from_string(expr, "").unwrap(); let attrs = es.require_attrs_names(&v).unwrap(); @@ -487,7 +499,7 @@ mod tests { fn eval_state_require_attrs_select() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let expr = r#"{ a = "aye"; b = "bee"; }"#; let v = es.eval_from_string(expr, "").unwrap(); let a = es.require_attrs_select(&v, "a").unwrap(); @@ -502,7 +514,7 @@ mod tests { fn eval_state_require_attrs_select_error() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let expr = r#"{ a = throw "oh no the error"; }"#; let v = es.eval_from_string(expr, "").unwrap(); let r = es.require_attrs_select(&v, "a"); @@ -523,7 +535,7 @@ mod tests { fn eval_state_require_attrs_select_opt() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let expr = r#"{ a = "aye"; b = "bee"; }"#; let v = es.eval_from_string(expr, "").unwrap(); let a = es.require_attrs_select_opt(&v, "a").unwrap().unwrap(); @@ -540,7 +552,7 @@ mod tests { fn eval_state_require_attrs_select_opt_error() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let expr = r#"{ a = throw "oh no the error"; }"#; let v = es.eval_from_string(expr, "").unwrap(); let r = es.require_attrs_select_opt(&v, "a"); @@ -561,7 +573,7 @@ mod tests { fn eval_state_value_string() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("\"hello\"", "").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -576,7 +588,7 @@ mod tests { fn eval_state_value_string_unexpected_bool() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("true", "").unwrap(); es.force(&v).unwrap(); let r = es.require_string(&v); @@ -594,7 +606,7 @@ mod tests { fn eval_state_value_string_unexpected_path_value() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("/foo", "").unwrap(); es.force(&v).unwrap(); let r = es.require_string(&v); @@ -611,7 +623,7 @@ mod tests { fn eval_state_value_string_bad_utf() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es .eval_from_string("builtins.substring 0 1 \"ΓΌ\"", "") .unwrap(); @@ -632,7 +644,7 @@ mod tests { fn eval_state_value_string_unexpected_context() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es .eval_from_string("(derivation { name = \"hello\"; system = \"dummy\"; builder = \"cmd.exe\"; }).outPath", "") .unwrap(); @@ -651,7 +663,7 @@ mod tests { fn eval_state_new_string() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.new_value_str("hello").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -666,7 +678,7 @@ mod tests { fn eval_state_new_string_empty() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.new_value_str("").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -681,7 +693,7 @@ mod tests { fn eval_state_new_string_invalid() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let r = es.new_value_str("hell\0no"); match r { Ok(_) => panic!("expected an error"), @@ -700,7 +712,7 @@ mod tests { fn eval_state_new_int() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.new_value_int(42).unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -715,7 +727,7 @@ mod tests { fn eval_state_value_attrset() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es.eval_from_string("{ }", "").unwrap(); es.force(&v).unwrap(); let t = es.value_type(&v).unwrap(); @@ -728,7 +740,7 @@ mod tests { fn eval_state_value_list() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let v = es .eval_from_string("[ ]", "") .unwrap(); @@ -743,7 +755,7 @@ mod tests { fn eval_state_realise_string() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let expr = r#" '' a derivation output: ${ @@ -790,7 +802,7 @@ mod tests { fn eval_state_call() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let f = es.eval_from_string("x: x + 1", "").unwrap(); let a = es.eval_from_string("2", "").unwrap(); let v = es.call(f, a).unwrap(); @@ -807,7 +819,7 @@ mod tests { fn eval_state_call_fail_body() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let f = es.eval_from_string("x: x + 1", "").unwrap(); let a = es.eval_from_string("true", "").unwrap(); let r = es.call(f, a); @@ -828,7 +840,7 @@ mod tests { fn eval_state_call_fail_args() { gc_registering_current_thread(|| { let store = Store::open("auto").unwrap(); - let es = EvalState::new(store).unwrap(); + let es = EvalState::new(store, []).unwrap(); let f = es.eval_from_string("{x}: x + 1", "").unwrap(); let a = es.eval_from_string("{}", "").unwrap(); let r = es.call(f, a);