diff --git a/src/machine/heap.rs b/src/machine/heap.rs index d9f1aa88..d8c52ac8 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -599,7 +599,7 @@ impl Heap { pub(crate) fn with_cell_capacity(cap: usize) -> Result { let ptr = unsafe { let layout = alloc::Layout::from_size_align( - cap * size_of::(), + heap_index_checked!(cap).ok_or(AllocError)?, size_of::(), ) .unwrap(); @@ -623,7 +623,7 @@ impl Heap { pub fn reserve(&mut self, num_cells: usize) -> Result, AllocError> { let section; - let len = heap_index!(num_cells); + let len = heap_index_checked!(num_cells).ok_or(AllocError)?; loop { unsafe { @@ -1148,7 +1148,9 @@ pub fn sized_iter_to_heap_list>( ) -> Result { if size > 0 { let h = heap.cell_len(); - let mut writer = heap.reserve(1 + 2 * size)?; + // not using checked_add for 1 + as the result of multiplying by 2 will be even and the largest representable usize is odd, + // so the addition cannot overflow + let mut writer = heap.reserve(1 + size.checked_mul(2).ok_or(AllocError)?)?; writer.write_with(|section| { for (idx, value) in values.enumerate() { diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index fa6822d0..4ed19893 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -76,7 +76,6 @@ impl ValidType { #[derive(Debug, Clone, Copy)] pub(crate) enum ResourceError { - FiniteMemory(HeapCellValue), OutOfFiles, } @@ -330,12 +329,6 @@ impl MachineState { pub(super) fn resource_error(err: ResourceError) -> MachineError { let stub = match err { - ResourceError::FiniteMemory(size_requested) => { - functor!( - atom!("resource_error"), - [atom_as_cell((atom!("finite_memory"))), cell(size_requested)] - ) - } ResourceError::OutOfFiles => { functor!( atom!("resource_error"), @@ -778,9 +771,16 @@ impl MachineState { // throw an error pre-allocated in the heap pub(super) fn throw_resource_error(&mut self, err: AllocError) { + if self.throwing_resource_error { + panic!("attempted to throw `error(resource_error(memory), [])` while attempting to throw `error(resource_error(memory), [])`"); + } + self.throwing_resource_error = true; + self.registers[1] = str_loc_as_cell!(err.resource_error_offset(&mut self.heap)); self.set_ball(); self.unwind_stack(); + + self.throwing_resource_error = false; } pub(super) fn throw_exception(&mut self, err: MachineStub) { diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 452debb2..732678da 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -74,6 +74,7 @@ pub struct MachineState { pub(super) cp: usize, pub(super) attr_var_init: AttrVarInitializer, pub(super) fail: bool, + pub throwing_resource_error: bool, pub heap: Heap, pub(super) mode: MachineMode, pub(crate) stack: Stack, diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index ee8a130b..7b777ae6 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -67,6 +67,7 @@ impl MachineState { unify_fn: MachineState::unify, bind_fn: MachineState::bind, run_cleaners_fn: |_| false, + throwing_resource_error: false, } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index b7a63aad..ac13c2e5 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -4371,7 +4371,6 @@ impl Machine { #[inline(always)] pub(crate) fn det_length_rundown(&mut self) -> CallResult { - let stub_gen = || functor_stub(atom!("length"), 2); let len = self.deref_register(2); let n = match Number::try_from((len, &self.machine_st.arena.f64_tbl)) { @@ -4379,8 +4378,8 @@ impl Machine { Ok(Number::Integer(n)) => match (&*n).try_into() as Result { Ok(n) => n, Err(_) => { - let err = MachineState::resource_error(ResourceError::FiniteMemory(len)); - return Err(self.machine_st.error_form(err, stub_gen())); + self.machine_st.throw_resource_error(AllocError); + return Ok(()); } }, _ => { diff --git a/src/macros.rs b/src/macros.rs index f977b882..7e7853dc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -470,12 +470,27 @@ macro_rules! resource_error_call_result { }; } -macro_rules! heap_index { +macro_rules! heap_index_checked { ($idx:expr) => { - ($idx) * std::mem::size_of::() + std::mem::size_of::().checked_mul($idx) }; } +pub(crate) use heap_index_checked; + +macro_rules! heap_index { + ($idx:expr) => {{ + let idx = $idx; + $crate::macros::heap_index_checked!(idx).unwrap_or_else(|| { + panic!( + "overflow while calculating heap index {idx} * {} > {}", + std::mem::size_of::(), + usize::MAX, + ) + }) + }}; +} + macro_rules! cell_index { ($idx:expr) => { ($idx) / std::mem::size_of::()