From 1df75a2caba10d456f9e8a43c1e86b6e2b37d97f Mon Sep 17 00:00:00 2001 From: Alex Shelkovnykov Date: Wed, 14 Feb 2024 12:50:37 +0900 Subject: [PATCH] Merge branch 'as/serf-guard' into msl/guard - manual - compiles - tests fail - doesn't run --- rust/ares/Cargo.lock | 10 +- rust/ares/Cargo.toml | 4 +- rust/ares/src/interpreter.rs | 1010 +++++++++-------- rust/ares/src/serf.rs | 23 +- rust/ares_crypto/Cargo.toml | 4 +- rust/ares_guard/c-src/guard.c | 228 ++-- rust/ares_guard/c-src/guard.h | 8 +- rust/ares_guard/src/lib.rs | 4 +- rust/ares_pma/c-src/btree.c | 1 + .../Cargo.toml | 0 .../LICENSE | 0 .../README.md | 0 .../examples/main.rs | 0 .../src/lib.rs | 18 + .../tests/test.rs | 0 15 files changed, 635 insertions(+), 675 deletions(-) rename rust/{assert-no-alloc => rust-assert-no-alloc}/Cargo.toml (100%) rename rust/{assert-no-alloc => rust-assert-no-alloc}/LICENSE (100%) rename rust/{assert-no-alloc => rust-assert-no-alloc}/README.md (100%) rename rust/{assert-no-alloc => rust-assert-no-alloc}/examples/main.rs (100%) rename rust/{assert-no-alloc => rust-assert-no-alloc}/src/lib.rs (92%) rename rust/{assert-no-alloc => rust-assert-no-alloc}/tests/test.rs (100%) diff --git a/rust/ares/Cargo.lock b/rust/ares/Cargo.lock index 02fe6dd..274c0b5 100644 --- a/rust/ares/Cargo.lock +++ b/rust/ares/Cargo.lock @@ -62,7 +62,7 @@ dependencies = [ "ares_guard", "ares_macros", "ares_pma", - "assert_no_alloc 1.1.2", + "assert_no_alloc", "autotools", "bitvec", "cc", @@ -87,7 +87,7 @@ version = "0.1.0" dependencies = [ "aes", "aes-siv", - "assert_no_alloc 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_no_alloc", "curve25519-dalek", "ed25519-dalek", "ibig 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -124,12 +124,6 @@ dependencies = [ name = "assert_no_alloc" version = "1.1.2" -[[package]] -name = "assert_no_alloc" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ca83137a482d61d916ceb1eba52a684f98004f18e0cafea230fe5579c178a3" - [[package]] name = "atty" version = "0.2.14" diff --git a/rust/ares/Cargo.toml b/rust/ares/Cargo.toml index 8928d11..3156e0d 100644 --- a/rust/ares/Cargo.toml +++ b/rust/ares/Cargo.toml @@ -18,8 +18,8 @@ ares_macros = { path = "../ares_macros" } # ares_pma = { path = "../ares_pma", features=["debug_prints"] } ares_pma = { path = "../ares_pma" } # use this when debugging requires allocation (e.g. eprintln) -# assert_no_alloc = { path = "../assert-no-alloc", features=["warn_debug"] } -assert_no_alloc = { path = "../assert-no-alloc" } +# assert_no_alloc = { path = "../rust-assert-no-alloc", features=["warn_debug"] } +assert_no_alloc = { path = "../rust-assert-no-alloc" } bitvec = "1.0.0" criterion = "0.4" either = "1.9.0" diff --git a/rust/ares/src/interpreter.rs b/rust/ares/src/interpreter.rs index 186ba3d..d7859ca 100644 --- a/rust/ares/src/interpreter.rs +++ b/rust/ares/src/interpreter.rs @@ -1,6 +1,7 @@ use crate::assert_acyclic; use crate::assert_no_forwarding_pointers; use crate::assert_no_junior_pointers; +use crate::guard::call_with_guard; use crate::hamt::Hamt; use crate::jets::cold; use crate::jets::cold::Cold; @@ -16,9 +17,9 @@ use crate::serf::TERMINATOR; use crate::trace::{write_nock_trace, TraceInfo, TraceStack}; use crate::unifying_equality::unifying_equality; use ares_macros::tas; -use assert_no_alloc::assert_no_alloc; +use assert_no_alloc::{assert_no_alloc, ensure_alloc_counters}; use bitvec::prelude::{BitSlice, Lsb0}; -use either::Either::*; +use either::*; use std::result; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -400,533 +401,560 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res // ``` // // (See https://docs.rs/assert_no_alloc/latest/assert_no_alloc/#advanced-use) - let nock = assert_no_alloc(|| unsafe { - push_formula(&mut context.stack, formula, true)?; + let nock = assert_no_alloc(|| { + ensure_alloc_counters(|| { + let stack_pp = context.stack.get_stack_pointer_pointer() as *const *const u64; + let alloc_pp = context.stack.get_alloc_pointer_pointer() as *const *const u64; + let work_f = &mut || unsafe { + push_formula(&mut context.stack, formula, true)?; - loop { - let work: NockWork = *context.stack.top(); - match work { - NockWork::Done => { - write_trace(context); + loop { + let work: NockWork = *context.stack.top(); + match work { + NockWork::Done => { + write_trace(context); - let stack = &mut context.stack; - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - stack.preserve(&mut context.cache); - stack.preserve(&mut context.cold); - stack.preserve(&mut context.warm); - stack.preserve(&mut res); - stack.frame_pop(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, res); - - break Ok(res); - } - NockWork::Ret => { - write_trace(context); - - let stack = &mut context.stack; - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - stack.preserve(&mut context.cache); - stack.preserve(&mut context.cold); - stack.preserve(&mut context.warm); - stack.preserve(&mut res); - stack.frame_pop(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, res); - } - NockWork::WorkCons(mut cons) => match cons.todo { - TodoCons::ComputeHead => { - cons.todo = TodoCons::ComputeTail; - *context.stack.top() = NockWork::WorkCons(cons); - push_formula(&mut context.stack, cons.head, false)?; - } - TodoCons::ComputeTail => { - cons.todo = TodoCons::Cons; - cons.head = res; - *context.stack.top() = NockWork::WorkCons(cons); - push_formula(&mut context.stack, cons.tail, false)?; - } - TodoCons::Cons => { - let stack = &mut context.stack; - res = T(stack, &[cons.head, res]); - stack.pop::(); - } - }, - NockWork::Work0(zero) => { - if let Ok(noun) = subject.slot_atom(zero.axis) { - res = noun; - context.stack.pop::(); - } else { - // Axis invalid for input Noun - break BAIL_EXIT; - } - } - NockWork::Work1(once) => { - res = once.noun; - context.stack.pop::(); - } - NockWork::Work2(mut vale) => { - if (*terminator).load(Ordering::Relaxed) { - break BAIL_INTR; - } - - match vale.todo { - Todo2::ComputeSubject => { - vale.todo = Todo2::ComputeFormula; - *context.stack.top() = NockWork::Work2(vale); - push_formula(&mut context.stack, vale.subject, false)?; - } - Todo2::ComputeFormula => { - vale.todo = Todo2::ComputeResult; - vale.subject = res; - *context.stack.top() = NockWork::Work2(vale); - push_formula(&mut context.stack, vale.formula, false)?; - } - Todo2::ComputeResult => { let stack = &mut context.stack; - if vale.tail { - stack.pop::(); - subject = vale.subject; - push_formula(stack, res, true)?; - } else { - vale.todo = Todo2::RestoreSubject; - std::mem::swap(&mut vale.subject, &mut subject); - *stack.top() = NockWork::Work2(vale); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - - mean_frame_push(stack, 0); - *stack.push() = NockWork::Ret; - push_formula(stack, res, true)?; - } - } - Todo2::RestoreSubject => { - let stack = &mut context.stack; - - subject = vale.subject; - stack.pop::(); - debug_assertions(stack, orig_subject); debug_assertions(stack, subject); debug_assertions(stack, res); + + stack.preserve(&mut context.cache); + stack.preserve(&mut context.cold); + stack.preserve(&mut context.warm); + stack.preserve(&mut res); + stack.frame_pop(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, res); + + break Ok(res); } - } - } - NockWork::Work3(mut thee) => match thee.todo { - Todo3::ComputeChild => { - thee.todo = Todo3::ComputeType; - *context.stack.top() = NockWork::Work3(thee); - push_formula(&mut context.stack, thee.child, false)?; - } - Todo3::ComputeType => { - res = if res.is_cell() { D(0) } else { D(1) }; - context.stack.pop::(); - } - }, - NockWork::Work4(mut four) => match four.todo { - Todo4::ComputeChild => { - four.todo = Todo4::Increment; - *context.stack.top() = NockWork::Work4(four); - push_formula(&mut context.stack, four.child, false)?; - } - Todo4::Increment => { - if let Ok(atom) = res.as_atom() { - res = inc(&mut context.stack, atom).as_noun(); - context.stack.pop::(); - } else { - // Cannot increment (Nock 4) a cell - break BAIL_EXIT; + NockWork::Ret => { + write_trace(context); + + let stack = &mut context.stack; + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + stack.preserve(&mut context.cache); + stack.preserve(&mut context.cold); + stack.preserve(&mut context.warm); + stack.preserve(&mut res); + stack.frame_pop(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, res); } - } - }, - NockWork::Work5(mut five) => match five.todo { - Todo5::ComputeLeftChild => { - five.todo = Todo5::ComputeRightChild; - *context.stack.top() = NockWork::Work5(five); - push_formula(&mut context.stack, five.left, false)?; - } - Todo5::ComputeRightChild => { - five.todo = Todo5::TestEquals; - five.left = res; - *context.stack.top() = NockWork::Work5(five); - push_formula(&mut context.stack, five.right, false)?; - } - Todo5::TestEquals => { - let stack = &mut context.stack; - let saved_value_ptr = &mut five.left; - res = if unifying_equality(stack, &mut res, saved_value_ptr) { - D(0) - } else { - D(1) - }; - stack.pop::(); - } - }, - NockWork::Work6(mut cond) => match cond.todo { - Todo6::ComputeTest => { - cond.todo = Todo6::ComputeBranch; - *context.stack.top() = NockWork::Work6(cond); - push_formula(&mut context.stack, cond.test, false)?; - } - Todo6::ComputeBranch => { - let stack = &mut context.stack; - stack.pop::(); - if let Left(direct) = res.as_either_direct_allocated() { - if direct.data() == 0 { - push_formula(stack, cond.zero, cond.tail)?; - } else if direct.data() == 1 { - push_formula(stack, cond.once, cond.tail)?; + NockWork::WorkCons(mut cons) => match cons.todo { + TodoCons::ComputeHead => { + cons.todo = TodoCons::ComputeTail; + *context.stack.top() = NockWork::WorkCons(cons); + push_formula(&mut context.stack, cons.head, false)?; + } + TodoCons::ComputeTail => { + cons.todo = TodoCons::Cons; + cons.head = res; + *context.stack.top() = NockWork::WorkCons(cons); + push_formula(&mut context.stack, cons.tail, false)?; + } + TodoCons::Cons => { + let stack = &mut context.stack; + res = T(stack, &[cons.head, res]); + stack.pop::(); + } + }, + NockWork::Work0(zero) => { + if let Ok(noun) = subject.slot_atom(zero.axis) { + res = noun; + context.stack.pop::(); } else { - // Test branch of Nock 6 must return 0 or 1 + // Axis invalid for input Noun break BAIL_EXIT; } - } else { - // Test branch of Nock 6 must return a direct atom - break BAIL_EXIT; } - } - }, - NockWork::Work7(mut pose) => match pose.todo { - Todo7::ComputeSubject => { - pose.todo = Todo7::ComputeResult; - *context.stack.top() = NockWork::Work7(pose); - push_formula(&mut context.stack, pose.subject, false)?; - } - Todo7::ComputeResult => { - let stack = &mut context.stack; - if pose.tail { - stack.pop::(); - subject = res; - push_formula(stack, pose.formula, true)?; - } else { - pose.todo = Todo7::RestoreSubject; - pose.subject = subject; - *stack.top() = NockWork::Work7(pose); - subject = res; - push_formula(stack, pose.formula, false)?; + NockWork::Work1(once) => { + res = once.noun; + context.stack.pop::(); } - } - Todo7::RestoreSubject => { - subject = pose.subject; - context.stack.pop::(); - } - }, - NockWork::Work8(mut pins) => match pins.todo { - Todo8::ComputeSubject => { - pins.todo = Todo8::ComputeResult; - *context.stack.top() = NockWork::Work8(pins); - push_formula(&mut context.stack, pins.pin, false)?; - } - Todo8::ComputeResult => { - let stack = &mut context.stack; - if pins.tail { - subject = T(stack, &[res, subject]); - stack.pop::(); - push_formula(stack, pins.formula, true)?; - } else { - pins.todo = Todo8::RestoreSubject; - pins.pin = subject; - *stack.top() = NockWork::Work8(pins); - subject = T(stack, &[res, subject]); - push_formula(stack, pins.formula, false)?; - } - } - Todo8::RestoreSubject => { - subject = pins.pin; - context.stack.pop::(); - } - }, - NockWork::Work9(mut kale) => { - if (*terminator).load(Ordering::Relaxed) { - break BAIL_INTR; - } + NockWork::Work2(mut vale) => { + if (*terminator).load(Ordering::Relaxed) { + break BAIL_INTR; + } - match kale.todo { - Todo9::ComputeCore => { - kale.todo = Todo9::ComputeResult; - *context.stack.top() = NockWork::Work9(kale); - push_formula(&mut context.stack, kale.core, false)?; - } - Todo9::ComputeResult => { - if let Ok(mut formula) = res.slot_atom(kale.axis) { - if !cfg!(feature = "sham_hints") { - if let Some((jet, _path)) = context.warm.find_jet( - &mut context.stack, - &mut res, - &mut formula, - ) { - match jet(context, res) { - Ok(jet_res) => { - res = jet_res; - context.stack.pop::(); - continue; - } - Err(JetErr::Punt) => {} - Err(err) => { - break Err(err.into()); - } - } + match vale.todo { + Todo2::ComputeSubject => { + vale.todo = Todo2::ComputeFormula; + *context.stack.top() = NockWork::Work2(vale); + push_formula(&mut context.stack, vale.subject, false)?; + } + Todo2::ComputeFormula => { + vale.todo = Todo2::ComputeResult; + vale.subject = res; + *context.stack.top() = NockWork::Work2(vale); + push_formula(&mut context.stack, vale.formula, false)?; + } + Todo2::ComputeResult => { + let stack = &mut context.stack; + if vale.tail { + stack.pop::(); + subject = vale.subject; + push_formula(stack, res, true)?; + } else { + vale.todo = Todo2::RestoreSubject; + std::mem::swap(&mut vale.subject, &mut subject); + *stack.top() = NockWork::Work2(vale); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + mean_frame_push(stack, 0); + *stack.push() = NockWork::Ret; + push_formula(stack, res, true)?; } - }; + } + Todo2::RestoreSubject => { + let stack = &mut context.stack; - let stack = &mut context.stack; - if kale.tail { + subject = vale.subject; stack.pop::(); - // We could trace on 2 as well, but 2 only comes from Hoon via - // '.*', so we can assume it's never directly used to invoke - // jetted code. - if context.trace_info.is_some() { - if let Some(path) = context.cold.matches(stack, &mut res) { - append_trace(stack, path); - }; - }; - - subject = res; - push_formula(stack, formula, true)?; - } else { - kale.todo = Todo9::RestoreSubject; - kale.core = subject; - *stack.top() = NockWork::Work9(kale); - debug_assertions(stack, orig_subject); debug_assertions(stack, subject); debug_assertions(stack, res); - - subject = res; - mean_frame_push(stack, 0); - *stack.push() = NockWork::Ret; - push_formula(stack, formula, true)?; - - // We could trace on 2 as well, but 2 only comes from Hoon via - // '.*', so we can assume it's never directly used to invoke - // jetted code. - if context.trace_info.is_some() { - if let Some(path) = context.cold.matches(stack, &mut res) { - append_trace(stack, path); - }; - }; - } - } else { - // Axis into core must be atom - break BAIL_EXIT; - } - } - Todo9::RestoreSubject => { - let stack = &mut context.stack; - - subject = kale.core; - stack.pop::(); - - debug_assertions(stack, orig_subject); - debug_assertions(stack, subject); - debug_assertions(stack, res); - } - } - } - NockWork::Work10(mut diet) => { - match diet.todo { - Todo10::ComputeTree => { - diet.todo = Todo10::ComputePatch; // should we compute patch then tree? - *context.stack.top() = NockWork::Work10(diet); - push_formula(&mut context.stack, diet.tree, false)?; - } - Todo10::ComputePatch => { - diet.todo = Todo10::Edit; - diet.tree = res; - *context.stack.top() = NockWork::Work10(diet); - push_formula(&mut context.stack, diet.patch, false)?; - } - Todo10::Edit => { - res = edit(&mut context.stack, diet.axis.as_bitslice(), res, diet.tree); - context.stack.pop::(); - } - } - } - NockWork::Work11D(mut dint) => match dint.todo { - Todo11D::ComputeHint => { - if let Some(ret) = - hint::match_pre_hint(context, subject, dint.tag, dint.hint, dint.body) - { - match ret { - Ok(found) => { - res = found; - context.stack.pop::(); - } - Err(err) => { - break Err(err); } } - } else { - dint.todo = Todo11D::ComputeResult; - *context.stack.top() = NockWork::Work11D(dint); - push_formula(&mut context.stack, dint.hint, false)?; } - } - Todo11D::ComputeResult => { - if let Some(ret) = hint::match_pre_nock( - context, - subject, - dint.tag, - Some((dint.hint, res)), - dint.body, - ) { - match ret { - Ok(found) => { - res = found; - context.stack.pop::(); - } - Err(err) => { - break Err(err); - } + NockWork::Work3(mut thee) => match thee.todo { + Todo3::ComputeChild => { + thee.todo = Todo3::ComputeType; + *context.stack.top() = NockWork::Work3(thee); + push_formula(&mut context.stack, thee.child, false)?; } - } else { - if dint.tail { + Todo3::ComputeType => { + res = if res.is_cell() { D(0) } else { D(1) }; context.stack.pop::(); - } else { - dint.todo = Todo11D::Done; - dint.hint = res; - *context.stack.top() = NockWork::Work11D(dint); } - push_formula(&mut context.stack, dint.body, dint.tail)?; - } - } - Todo11D::Done => { - if let Some(found) = hint::match_post_nock( - context, - subject, - dint.tag, - Some(dint.hint), - dint.body, - res, - ) { - res = found; - } - context.stack.pop::(); - } - }, - NockWork::Work11S(mut sint) => match sint.todo { - Todo11S::ComputeResult => { - if let Some(ret) = - hint::match_pre_nock(context, subject, sint.tag, None, sint.body) - { - match ret { - Ok(found) => { - res = found; + }, + NockWork::Work4(mut four) => match four.todo { + Todo4::ComputeChild => { + four.todo = Todo4::Increment; + *context.stack.top() = NockWork::Work4(four); + push_formula(&mut context.stack, four.child, false)?; + } + Todo4::Increment => { + if let Ok(atom) = res.as_atom() { + res = inc(&mut context.stack, atom).as_noun(); context.stack.pop::(); - } - Err(err) => { - break Err(err); + } else { + // Cannot increment (Nock 4) a cell + break BAIL_EXIT; } } - } else { - if sint.tail { - context.stack.pop::(); - } else { - sint.todo = Todo11S::Done; - *context.stack.top() = NockWork::Work11S(sint); + }, + NockWork::Work5(mut five) => match five.todo { + Todo5::ComputeLeftChild => { + five.todo = Todo5::ComputeRightChild; + *context.stack.top() = NockWork::Work5(five); + push_formula(&mut context.stack, five.left, false)?; } - push_formula(&mut context.stack, sint.body, sint.tail)?; - } - } - Todo11S::Done => { - if let Some(found) = - hint::match_post_nock(context, subject, sint.tag, None, sint.body, res) - { - res = found; - } - context.stack.pop::(); - } - }, - NockWork::Work12(mut scry) => match scry.todo { - Todo12::ComputeReff => { - let stack = &mut context.stack; - scry.todo = Todo12::ComputePath; - *stack.top() = NockWork::Work12(scry); - push_formula(stack, scry.reff, false)?; - } - Todo12::ComputePath => { - let stack = &mut context.stack; - scry.todo = Todo12::Scry; - scry.reff = res; - *stack.top() = NockWork::Work12(scry); - push_formula(stack, scry.path, false)?; - } - Todo12::Scry => { - if let Some(cell) = context.scry_stack.cell() { - scry.path = res; - let scry_stack = context.scry_stack; - let scry_handler = cell.head(); - let scry_gate = scry_handler.as_cell()?; - let payload = T(&mut context.stack, &[scry.reff, res]); - let scry_core = T( - &mut context.stack, - &[ - scry_gate.head(), - payload, - scry_gate.tail().as_cell()?.tail(), - ], - ); - let scry_form = T(&mut context.stack, &[D(9), D(2), D(1), scry_core]); - - context.scry_stack = cell.tail(); - // Alternately, we could use scry_core as the subject and [9 2 0 1] as - // the formula. It's unclear if performance will be better with a purely - // static formula. - match interpret(context, D(0), scry_form) { - Ok(noun) => match noun.as_either_atom_cell() { - Left(atom) => { - if atom.as_noun().raw_equals(D(0)) { - break Err(Error::ScryBlocked(scry.path)); - } else { - break Err(Error::ScryCrashed(D(0))); - } + Todo5::ComputeRightChild => { + five.todo = Todo5::TestEquals; + five.left = res; + *context.stack.top() = NockWork::Work5(five); + push_formula(&mut context.stack, five.right, false)?; + } + Todo5::TestEquals => { + let stack = &mut context.stack; + let saved_value_ptr = &mut five.left; + res = if unifying_equality(stack, &mut res, saved_value_ptr) { + D(0) + } else { + D(1) + }; + stack.pop::(); + } + }, + NockWork::Work6(mut cond) => match cond.todo { + Todo6::ComputeTest => { + cond.todo = Todo6::ComputeBranch; + *context.stack.top() = NockWork::Work6(cond); + push_formula(&mut context.stack, cond.test, false)?; + } + Todo6::ComputeBranch => { + let stack = &mut context.stack; + stack.pop::(); + if let Left(direct) = res.as_either_direct_allocated() { + if direct.data() == 0 { + push_formula(stack, cond.zero, cond.tail)?; + } else if direct.data() == 1 { + push_formula(stack, cond.once, cond.tail)?; + } else { + // Test branch of Nock 6 must return 0 or 1 + break BAIL_EXIT; } - Right(cell) => match cell.tail().as_either_atom_cell() { - Left(_) => { - let stack = &mut context.stack; - let hunk = - T(stack, &[D(tas!(b"hunk")), scry.reff, scry.path]); - mean_push(stack, hunk); - break Err(Error::ScryCrashed(D(0))); + } else { + // Test branch of Nock 6 must return a direct atom + break BAIL_EXIT; + } + } + }, + NockWork::Work7(mut pose) => match pose.todo { + Todo7::ComputeSubject => { + pose.todo = Todo7::ComputeResult; + *context.stack.top() = NockWork::Work7(pose); + push_formula(&mut context.stack, pose.subject, false)?; + } + Todo7::ComputeResult => { + let stack = &mut context.stack; + if pose.tail { + stack.pop::(); + subject = res; + push_formula(stack, pose.formula, true)?; + } else { + pose.todo = Todo7::RestoreSubject; + pose.subject = subject; + *stack.top() = NockWork::Work7(pose); + subject = res; + push_formula(stack, pose.formula, false)?; + } + } + Todo7::RestoreSubject => { + subject = pose.subject; + context.stack.pop::(); + } + }, + NockWork::Work8(mut pins) => match pins.todo { + Todo8::ComputeSubject => { + pins.todo = Todo8::ComputeResult; + *context.stack.top() = NockWork::Work8(pins); + push_formula(&mut context.stack, pins.pin, false)?; + } + Todo8::ComputeResult => { + let stack = &mut context.stack; + if pins.tail { + subject = T(stack, &[res, subject]); + stack.pop::(); + push_formula(stack, pins.formula, true)?; + } else { + pins.todo = Todo8::RestoreSubject; + pins.pin = subject; + *stack.top() = NockWork::Work8(pins); + subject = T(stack, &[res, subject]); + push_formula(stack, pins.formula, false)?; + } + } + Todo8::RestoreSubject => { + subject = pins.pin; + context.stack.pop::(); + } + }, + NockWork::Work9(mut kale) => { + if (*terminator).load(Ordering::Relaxed) { + break BAIL_INTR; + } + + match kale.todo { + Todo9::ComputeCore => { + kale.todo = Todo9::ComputeResult; + *context.stack.top() = NockWork::Work9(kale); + push_formula(&mut context.stack, kale.core, false)?; + } + Todo9::ComputeResult => { + if let Ok(mut formula) = res.slot_atom(kale.axis) { + if !cfg!(feature = "sham_hints") { + if let Some((jet, _path)) = context.warm.find_jet( + &mut context.stack, + &mut res, + &mut formula, + ) { + match jet(context, res) { + Ok(jet_res) => { + res = jet_res; + context.stack.pop::(); + continue; + } + Err(JetErr::Punt) => {} + Err(err) => { + break Err(err.into()); + } + } + } + }; + + let stack = &mut context.stack; + if kale.tail { + stack.pop::(); + + // We could trace on 2 as well, but 2 only comes from Hoon via + // '.*', so we can assume it's never directly used to invoke + // jetted code. + if context.trace_info.is_some() { + if let Some(path) = + context.cold.matches(stack, &mut res) + { + append_trace(stack, path); + }; + }; + + subject = res; + push_formula(stack, formula, true)?; + } else { + kale.todo = Todo9::RestoreSubject; + kale.core = subject; + *stack.top() = NockWork::Work9(kale); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + + subject = res; + mean_frame_push(stack, 0); + *stack.push() = NockWork::Ret; + push_formula(stack, formula, true)?; + + // We could trace on 2 as well, but 2 only comes from Hoon via + // '.*', so we can assume it's never directly used to invoke + // jetted code. + if context.trace_info.is_some() { + if let Some(path) = + context.cold.matches(stack, &mut res) + { + append_trace(stack, path); + }; + }; } - Right(cell) => { - res = cell.tail(); - context.scry_stack = scry_stack; + } else { + // Axis into core must be atom + break BAIL_EXIT; + } + } + Todo9::RestoreSubject => { + let stack = &mut context.stack; + + subject = kale.core; + stack.pop::(); + + debug_assertions(stack, orig_subject); + debug_assertions(stack, subject); + debug_assertions(stack, res); + } + } + } + NockWork::Work10(mut diet) => { + match diet.todo { + Todo10::ComputeTree => { + diet.todo = Todo10::ComputePatch; // should we compute patch then tree? + *context.stack.top() = NockWork::Work10(diet); + push_formula(&mut context.stack, diet.tree, false)?; + } + Todo10::ComputePatch => { + diet.todo = Todo10::Edit; + diet.tree = res; + *context.stack.top() = NockWork::Work10(diet); + push_formula(&mut context.stack, diet.patch, false)?; + } + Todo10::Edit => { + res = edit( + &mut context.stack, + diet.axis.as_bitslice(), + res, + diet.tree, + ); + context.stack.pop::(); + } + } + } + NockWork::Work11D(mut dint) => match dint.todo { + Todo11D::ComputeHint => { + if let Some(ret) = hint::match_pre_hint( + context, subject, dint.tag, dint.hint, dint.body, + ) { + match ret { + Ok(found) => { + res = found; context.stack.pop::(); } - }, - }, - Err(error) => match error { - Error::Deterministic(_, trace) | Error::ScryCrashed(trace) => { - break Err(Error::ScryCrashed(trace)); + Err(err) => { + break Err(err); + } } - Error::NonDeterministic(_, _) => { - break Err(error); - } - Error::ScryBlocked(_) => { - break BAIL_FAIL; - } - }, + } else { + dint.todo = Todo11D::ComputeResult; + *context.stack.top() = NockWork::Work11D(dint); + push_formula(&mut context.stack, dint.hint, false)?; + } } - } else { - // No scry handler - break BAIL_EXIT; - } - } - }, + Todo11D::ComputeResult => { + if let Some(ret) = hint::match_pre_nock( + context, + subject, + dint.tag, + Some((dint.hint, res)), + dint.body, + ) { + match ret { + Ok(found) => { + res = found; + context.stack.pop::(); + } + Err(err) => { + break Err(err); + } + } + } else { + if dint.tail { + context.stack.pop::(); + } else { + dint.todo = Todo11D::Done; + dint.hint = res; + *context.stack.top() = NockWork::Work11D(dint); + } + push_formula(&mut context.stack, dint.body, dint.tail)?; + } + } + Todo11D::Done => { + if let Some(found) = hint::match_post_nock( + context, + subject, + dint.tag, + Some(dint.hint), + dint.body, + res, + ) { + res = found; + } + context.stack.pop::(); + } + }, + NockWork::Work11S(mut sint) => match sint.todo { + Todo11S::ComputeResult => { + if let Some(ret) = hint::match_pre_nock( + context, subject, sint.tag, None, sint.body, + ) { + match ret { + Ok(found) => { + res = found; + context.stack.pop::(); + } + Err(err) => { + break Err(err); + } + } + } else { + if sint.tail { + context.stack.pop::(); + } else { + sint.todo = Todo11S::Done; + *context.stack.top() = NockWork::Work11S(sint); + } + push_formula(&mut context.stack, sint.body, sint.tail)?; + } + } + Todo11S::Done => { + if let Some(found) = hint::match_post_nock( + context, subject, sint.tag, None, sint.body, res, + ) { + res = found; + } + context.stack.pop::(); + } + }, + NockWork::Work12(mut scry) => match scry.todo { + Todo12::ComputeReff => { + let stack = &mut context.stack; + scry.todo = Todo12::ComputePath; + *stack.top() = NockWork::Work12(scry); + push_formula(stack, scry.reff, false)?; + } + Todo12::ComputePath => { + let stack = &mut context.stack; + scry.todo = Todo12::Scry; + scry.reff = res; + *stack.top() = NockWork::Work12(scry); + push_formula(stack, scry.path, false)?; + } + Todo12::Scry => { + if let Some(cell) = context.scry_stack.cell() { + scry.path = res; + let scry_stack = context.scry_stack; + let scry_handler = cell.head(); + let scry_gate = scry_handler.as_cell()?; + let payload = T(&mut context.stack, &[scry.reff, res]); + let scry_core = T( + &mut context.stack, + &[ + scry_gate.head(), + payload, + scry_gate.tail().as_cell()?.tail(), + ], + ); + let scry_form = + T(&mut context.stack, &[D(9), D(2), D(1), scry_core]); + + context.scry_stack = cell.tail(); + // Alternately, we could use scry_core as the subject and [9 2 0 1] as + // the formula. It's unclear if performance will be better with a purely + // static formula. + match interpret(context, D(0), scry_form) { + Ok(noun) => match noun.as_either_atom_cell() { + Left(atom) => { + if atom.as_noun().raw_equals(D(0)) { + break Err(Error::ScryBlocked(scry.path)); + } else { + break Err(Error::ScryCrashed(D(0))); + } + } + Right(cell) => { + match cell.tail().as_either_atom_cell() { + Left(_) => { + let stack = &mut context.stack; + let hunk = T( + stack, + &[ + D(tas!(b"hunk")), + scry.reff, + scry.path, + ], + ); + mean_push(stack, hunk); + break Err(Error::ScryCrashed(D(0))); + } + Right(cell) => { + res = cell.tail(); + context.scry_stack = scry_stack; + context.stack.pop::(); + } + } + } + }, + Err(error) => match error { + Error::Deterministic(_, trace) + | Error::ScryCrashed(trace) => { + break Err(Error::ScryCrashed(trace)); + } + Error::NonDeterministic(_, _) => { + break Err(error); + } + Error::ScryBlocked(_) => { + break BAIL_FAIL; + } + }, + } + } else { + // No scry handler + break BAIL_EXIT; + } + } + }, + }; + } }; - } + + call_with_guard(stack_pp, alloc_pp, work_f) + }) }); match nock { diff --git a/rust/ares/src/serf.rs b/rust/ares/src/serf.rs index 8da4e92..70632f1 100644 --- a/rust/ares/src/serf.rs +++ b/rust/ares/src/serf.rs @@ -1,4 +1,3 @@ -use crate::guard::call_with_guard; use crate::hamt::Hamt; use crate::interpreter; use crate::interpreter::{inc, interpret, Error, Mote}; @@ -403,27 +402,7 @@ fn slam(context: &mut Context, axis: u64, ovo: Noun) -> Result { let fol = T(stack, &[D(8), pul, D(9), D(2), D(10), sam, D(0), D(2)]); let sub = T(stack, &[arvo, ovo]); - let frame_p = stack.get_frame_pointer(); - let stack_pp = stack.get_stack_pointer_pointer(); - let alloc_pp = stack.get_alloc_pointer_pointer(); - - let res = call_with_guard( - stack_pp as *const *const u64, - alloc_pp as *const *const u64, - &mut || interpret(&mut context.nock_context, sub, fol), - ); - - if let Err(Error::NonDeterministic(Mote::Meme, _)) = res { - unsafe { - let stack = &mut context.nock_context.stack; - assert_no_alloc::reset_counters(); - while stack.get_frame_pointer() != frame_p { - stack.frame_pop(); - } - } - } - - res + interpret(&mut context.nock_context, sub, fol) } fn peek(context: &mut Context, ovo: Noun) -> Noun { diff --git a/rust/ares_crypto/Cargo.toml b/rust/ares_crypto/Cargo.toml index a52b57b..3ee2ab1 100644 --- a/rust/ares_crypto/Cargo.toml +++ b/rust/ares_crypto/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] # use this when debugging requires allocation (e.g. eprintln) -# assert_no_alloc = {version="1.1.2", features=["warn_debug"]} -assert_no_alloc = "1.1.2" +# assert_no_alloc = { path = "../rust-assert-no-alloc", features=["warn_debug"] } +assert_no_alloc = { path = "../rust-assert-no-alloc" } ibig = "0.3.6" # ed25519 diff --git a/rust/ares_guard/c-src/guard.c b/rust/ares_guard/c-src/guard.c index 8aa71f4..4557041 100644 --- a/rust/ares_guard/c-src/guard.c +++ b/rust/ares_guard/c-src/guard.c @@ -15,19 +15,11 @@ #define GD_PAGE_MASK (GD_PAGE_SIZE - 1) #define GD_PAGE_ROUND_DOWN(foo) (foo & (~GD_PAGE_MASK)) -/** - * XX: documentation - */ -typedef struct _gs { - uintptr_t guard_p; - const uintptr_t *stack_pp; - const uintptr_t *alloc_pp; - jmp_buf env_buffer; - struct sigaction prev_sa; -} GuardState; - -static GuardState *_guard_state = NULL; - +static uintptr_t guard_p; +static const uintptr_t *stack_pp; +static const uintptr_t *alloc_pp; +static jmp_buf env_buffer; +static struct sigaction prev_sa; static int32_t _prot_page(void *address, int prot) @@ -53,18 +45,21 @@ _unmark_page(void *address) return _prot_page(address, PROT_READ | PROT_WRITE); } -/** - * Center the guard page. - */ +// Center the guard page. +// XX: could be a false positive if the new frame results in exact same guard page +// solution: we only re-center from the signal handler static int32_t -_focus_guard( - uintptr_t *guard_pp, - const uintptr_t stack_p, - const uintptr_t alloc_p -) { - // Check for strange situations. +_focus_guard() +{ + uintptr_t stack_p = *stack_pp; + uintptr_t alloc_p = *alloc_pp; + uintptr_t old_guard_p = guard_p; + uintptr_t new_guard_p; + int32_t err = 0; + fprintf(stderr, "guard: focus: stack pointer at %p\r\n", (void *)stack_p); fprintf(stderr, "guard: focus: alloc pointer at %p\r\n", (void *)alloc_p); + if (stack_p == 0 || alloc_p == 0) { fprintf(stderr, "guard: focus: stack or alloc pointer is null\r\n"); return guard_null; @@ -73,20 +68,8 @@ _focus_guard( return guard_oom; } - uintptr_t old_guard_p = *guard_pp; - uintptr_t new_guard_p; - int32_t err = 0; - fprintf(stderr, "guard: focus: old guard = %p\r\n", (void *)old_guard_p); - // Unmark the old guard page (if there is one) - if (old_guard_p) { - if ((err = _unmark_page((void *)old_guard_p))) { - fprintf(stderr, "guard: focus: unmark error\r\n"); - return err; - } - } - // Compute new guard page // XX: Should we also check for new_guard_p < min(stack_p, alloc_p)? new_guard_p = GD_PAGE_ROUND_DOWN((stack_p + alloc_p) / 2); @@ -104,45 +87,50 @@ _focus_guard( // Update guard page tracker fprintf(stderr, "guard: focus: installed guard page at %p\r\n", (void *)new_guard_p); - *guard_pp = new_guard_p; - + guard_p = new_guard_p; + + // Unmark the old guard page (if there is one) + if (old_guard_p) { + if ((err = _unmark_page((void *)old_guard_p))) { + fprintf(stderr, "guard: focus: unmark error\r\n"); + return err; + } + } + return 0; } -void +static void _signal_handler(int sig, siginfo_t *si, void *unused) { uintptr_t sig_addr; int32_t err = 0; + assert(guard_p); + fprintf(stderr, "guard: sig_handle: %d received\r\n", sig); if (sig != SIGSEGV) { fprintf(stderr, "guard: sig_handle: invalid signal\r\n"); - siglongjmp(_guard_state->env_buffer, guard_signal); + // XX: do we even want to jump? if this is fatal error, maybe just die now + siglongjmp(env_buffer, guard_signal); } sig_addr = (uintptr_t)si->si_addr; fprintf(stderr, "guard: SIGSEGV address = %p\r\n", (void *)sig_addr); - fprintf(stderr, "guard: sig_handle: %p \r\n", _guard_state); - if ( - sig_addr >= _guard_state->guard_p && - sig_addr < (_guard_state->guard_p + GD_PAGE_SIZE)) + if (sig_addr >= guard_p && + sig_addr < guard_p + GD_PAGE_SIZE) { - fprintf(stderr, "guard: page at %p hit\r\n", (void *)_guard_state->guard_p); - err = _focus_guard( - &(_guard_state->guard_p), - *(_guard_state->stack_pp), - *(_guard_state->alloc_pp)); + fprintf(stderr, "guard: hit: %p\r\n", si->si_addr); + err = _focus_guard(); if (err) { fprintf(stderr, "guard: sig_handle: focus error\r\n"); - siglongjmp(_guard_state->env_buffer, err); + siglongjmp(env_buffer, err); } - } else { - struct sigaction prev_sa = _guard_state->prev_sa; - - fprintf(stderr, "guard: page at %p miss\r\n", (void *)_guard_state->guard_p); + } + else { + fprintf(stderr, "guard: page at %p miss\r\n", (void *)guard_p); if (prev_sa.sa_sigaction != NULL) { prev_sa.sa_sigaction(sig, si, unused); @@ -155,8 +143,8 @@ _signal_handler(int sig, siginfo_t *si, void *unused) } } -int32_t -_register_handler(struct sigaction *prev_sa) +static int32_t +_register_handler() { struct sigaction sa; @@ -171,8 +159,8 @@ _register_handler(struct sigaction *prev_sa) // sigemptyset(&sa.sa_mask); // sigaddset(&(sa.sa_mask), SIGSEGV); - // Set the new SIGSEGV handler, and save the old SIGSEGV handler (if any) - if (sigaction(SIGSEGV, &sa, prev_sa)) { + // XX: should assert that prev_sa doesn't have a handler in it, but it's not a pointer so non-trivial + if (sigaction(SIGSEGV, &sa, &prev_sa)) { fprintf(stderr, "guard: register: sigaction error\r\n"); fprintf(stderr, "%s\r\n", strerror(errno)); return guard_sigaction | errno; @@ -181,107 +169,59 @@ _register_handler(struct sigaction *prev_sa) return 0; } -int32_t -_setup( - GuardState **gs_p, - const uintptr_t *const stack_pp, - const uintptr_t *const alloc_pp -) { - GuardState *gs; - int32_t err = 0; - - assert(*gs_p == NULL); - fprintf(stderr, "guard: setup: stack pointer at %p\r\n", (void *)(*stack_pp)); - fprintf(stderr, "guard: setup: alloc pointer at %p\r\n", (void *)(*alloc_pp)); - - // Setup guard page state - *gs_p = (GuardState *)malloc(sizeof(GuardState)); - gs = *gs_p; - if (gs == NULL) { - fprintf(stderr, "guard: malloc error\r\n"); - fprintf(stderr, "%s\r\n", strerror(errno)); - return guard_malloc | errno; - } - fprintf(stderr, "guard: state allocated to %p \r\n", gs); - - gs->guard_p = 0; - gs->stack_pp = stack_pp; - gs->alloc_pp = alloc_pp; - - // Initialize the guard page - if ((err = _focus_guard(&(gs->guard_p), *stack_pp, *alloc_pp))) { - fprintf(stderr, "guard: setup: _focus_guard error\r\n"); - return err; - } - - // Register guard page signal handler - if ((err = _register_handler(&(gs->prev_sa)))) { - fprintf(stderr, "guard: setup: _register_handler error\r\n"); - return err; - } - - return 0; -} - -int32_t -_teardown(GuardState** gs_p) -{ - int32_t err = 0; - - if (*gs_p != NULL) { - GuardState *gs = *gs_p; - - if (gs->guard_p != 0) { - err = _unmark_page((void *)gs->guard_p); - } - - if (sigaction(SIGSEGV, &(gs->prev_sa), NULL)) { - fprintf(stderr, "guard: teardown: sigaction error\r\n"); - fprintf(stderr, "%s\r\n", strerror(errno)); - err = guard_sigaction | errno; - } - - free(gs); - *gs_p = NULL; - } - - return err; -} - int32_t guard( callback f, void *closure, - const uintptr_t *const stack_pp, - const uintptr_t *const alloc_pp, + const uintptr_t *const s_pp, + const uintptr_t *const a_pp, void ** ret ) { int32_t err = 0; + int32_t td_err; - // Setup the guard page - fprintf(stderr, "guard: setup\r\n"); - if ((err = _setup(&_guard_state, stack_pp, alloc_pp))) { + assert(guard_p == 0); + fprintf(stderr, "guard: setup: stack pointer at %p\r\n", (void *)(*stack_pp)); + fprintf(stderr, "guard: setup: alloc pointer at %p\r\n", (void *)(*alloc_pp)); + + guard_p = 0; + stack_pp = s_pp; + alloc_pp = a_pp; + + // Initialize the guard page + if ((err = _focus_guard())) { + fprintf(stderr, "guard: setup: _focus_guard error\r\n"); + goto done; + } + + // Register guard page signal handler + if ((err = _register_handler())) { + fprintf(stderr, "guard: setup: _register_handler error\r\n"); goto done; } // Run given closure fprintf(stderr, "guard: run\r\n"); - if (!(err = sigsetjmp(_guard_state->env_buffer, 1))) { + if (!(err = sigsetjmp(env_buffer, 1))) { *ret = f(closure); - - // Clean up - fprintf(stderr, "guard: teardown\r\n"); - err = _teardown(&_guard_state); - - fprintf(stderr, "guard: return\r\n"); - return err; - } else { -done: - // Clean up - fprintf(stderr, "guard: teardown\r\n"); - _teardown(&_guard_state); - - fprintf(stderr, "guard: return\r\n"); - return err; } + +done: + // Clean up + if (guard_p != 0) { + td_err = _unmark_page((void *)guard_p); + } + + if (sigaction(SIGSEGV, &prev_sa, NULL)) { + fprintf(stderr, "guard: teardown: sigaction error\r\n"); + fprintf(stderr, "%s\r\n", strerror(errno)); + td_err = guard_sigaction | errno; + } + + if (!err) { + err = td_err; + } + + fprintf(stderr, "guard: return\r\n"); + return err; } diff --git a/rust/ares_guard/c-src/guard.h b/rust/ares_guard/c-src/guard.h index fd08343..ae23815 100644 --- a/rust/ares_guard/c-src/guard.h +++ b/rust/ares_guard/c-src/guard.h @@ -5,7 +5,7 @@ /** * Error codes and flags. - * + * * The flags are bitwise added to the errno of their respective errors. */ typedef enum { @@ -51,9 +51,9 @@ int32_t guard( callback f, void *closure, - const uintptr_t *const stack_pp, - const uintptr_t *const alloc_pp, - void ** ret + const uintptr_t *const s_pp, + const uintptr_t *const a_pp, + void **ret ); #endif // __GUARD_H__ diff --git a/rust/ares_guard/src/lib.rs b/rust/ares_guard/src/lib.rs index 38e6c3c..c10fb5a 100644 --- a/rust/ares_guard/src/lib.rs +++ b/rust/ares_guard/src/lib.rs @@ -4,8 +4,8 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -pub const GUARD_NULL: u32 = guard_err_guard_null; -pub const GUARD_SIGNAL: u32 = guard_err_guard_signal; +pub const GUARD_NULL: u32 = guard_err_guard_null; +pub const GUARD_SIGNAL: u32 = guard_err_guard_signal; pub const GUARD_OOM: u32 = guard_err_guard_oom; pub const GUARD_MALLOC: u32 = guard_err_guard_malloc; pub const GUARD_MPROTECT: u32 = guard_err_guard_mprotect; diff --git a/rust/ares_pma/c-src/btree.c b/rust/ares_pma/c-src/btree.c index 4b2efd2..9ecf982 100644 --- a/rust/ares_pma/c-src/btree.c +++ b/rust/ares_pma/c-src/btree.c @@ -1567,6 +1567,7 @@ _flist_grow(BT_state *state, size_t pages) /* grows the backing file by PMA_GROW_SIZE_p and appends this freespace to the flist */ { + exit(1); /* grow the backing file by at least PMA_GROW_SIZE_p */ pages = MAX(pages, PMA_GROW_SIZE_p); off_t bytes = P2BYTES(pages); diff --git a/rust/assert-no-alloc/Cargo.toml b/rust/rust-assert-no-alloc/Cargo.toml similarity index 100% rename from rust/assert-no-alloc/Cargo.toml rename to rust/rust-assert-no-alloc/Cargo.toml diff --git a/rust/assert-no-alloc/LICENSE b/rust/rust-assert-no-alloc/LICENSE similarity index 100% rename from rust/assert-no-alloc/LICENSE rename to rust/rust-assert-no-alloc/LICENSE diff --git a/rust/assert-no-alloc/README.md b/rust/rust-assert-no-alloc/README.md similarity index 100% rename from rust/assert-no-alloc/README.md rename to rust/rust-assert-no-alloc/README.md diff --git a/rust/assert-no-alloc/examples/main.rs b/rust/rust-assert-no-alloc/examples/main.rs similarity index 100% rename from rust/assert-no-alloc/examples/main.rs rename to rust/rust-assert-no-alloc/examples/main.rs diff --git a/rust/assert-no-alloc/src/lib.rs b/rust/rust-assert-no-alloc/src/lib.rs similarity index 92% rename from rust/assert-no-alloc/src/lib.rs rename to rust/rust-assert-no-alloc/src/lib.rs index 00f6a92..0e2b0aa 100644 --- a/rust/assert-no-alloc/src/lib.rs +++ b/rust/rust-assert-no-alloc/src/lib.rs @@ -91,6 +91,23 @@ pub fn assert_no_alloc T> (func: F) -> T { return ret; } +#[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled +/// Calls the `func` closure, but ensures that the forbid and permit counters +/// are maintained accurately even if a longjmp originates and terminates +/// within the closure. If you longjmp over this function, we can't fix +/// anything about it. +pub fn ensure_alloc_counters T> (func: F) -> T { + let forbid_counter = ALLOC_FORBID_COUNT.with(|c| c.get()); + let permit_counter = ALLOC_PERMIT_COUNT.with(|c| c.get()); + + let ret = func(); + + ALLOC_FORBID_COUNT.with(|c| c.set(forbid_counter)); + ALLOC_PERMIT_COUNT.with(|c| c.set(permit_counter)); + + return ret; +} + #[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled /// Calls the `func` closure. Allocations are temporarily allowed, even if this /// code runs inside of assert_no_alloc. @@ -142,6 +159,7 @@ pub fn reset_counters() { + #[cfg(not(all(feature = "disable_release", not(debug_assertions))))] // if not disabled /// The custom allocator that handles the checking. /// diff --git a/rust/assert-no-alloc/tests/test.rs b/rust/rust-assert-no-alloc/tests/test.rs similarity index 100% rename from rust/assert-no-alloc/tests/test.rs rename to rust/rust-assert-no-alloc/tests/test.rs