Skip to content
8 changes: 5 additions & 3 deletions src/machine/heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ impl Heap {
pub(crate) fn with_cell_capacity(cap: usize) -> Result<Self, AllocError> {
let ptr = unsafe {
let layout = alloc::Layout::from_size_align(
cap * size_of::<HeapCellValue>(),
heap_index_checked!(cap).ok_or(AllocError)?,
size_of::<HeapCellValue>(),
)
.unwrap();
Expand All @@ -623,7 +623,7 @@ impl Heap {

pub fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, AllocError> {
let section;
let len = heap_index!(num_cells);
let len = heap_index_checked!(num_cells).ok_or(AllocError)?;

loop {
unsafe {
Expand Down Expand Up @@ -1148,7 +1148,9 @@ pub fn sized_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
) -> Result<HeapCellValue, AllocError> {
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() {
Expand Down
44 changes: 41 additions & 3 deletions src/machine/machine_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,9 +778,47 @@ impl MachineState {

// throw an error pre-allocated in the heap
pub(super) fn throw_resource_error(&mut self, err: AllocError) {
self.registers[1] = str_loc_as_cell!(err.resource_error_offset(&mut self.heap));
self.set_ball();
self.unwind_stack();
struct RecursionGuard<'state> {
machine_state: &'state mut MachineState,
}
Comment thread
Skgland marked this conversation as resolved.
Outdated

impl<'state> RecursionGuard<'state> {
fn new(machine_state: &'state mut MachineState) -> Self {
if machine_state.throwing_resource_error {
panic!("attempted to throw `error(resource_error(memory), [])` while attempting to throw `error(resource_error(memory), [])`");
}
machine_state.throwing_resource_error = true;
Self { machine_state }
}
}

impl Drop for RecursionGuard<'_> {
fn drop(&mut self) {
self.machine_state.throwing_resource_error = false;
}
}

impl std::ops::Deref for RecursionGuard<'_> {
type Target = MachineState;

fn deref(&self) -> &MachineState {
self.machine_state
}
}

impl std::ops::DerefMut for RecursionGuard<'_> {
fn deref_mut(&mut self) -> &mut MachineState {
self.machine_state
}
}

let mut guard = RecursionGuard::new(self);

let state = &mut *guard;

state.registers[1] = str_loc_as_cell!(err.resource_error_offset(&mut state.heap));
state.set_ball();
state.unwind_stack();
}

pub(super) fn throw_exception(&mut self, err: MachineStub) {
Expand Down
1 change: 1 addition & 0 deletions src/machine/machine_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/machine/machine_state_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl MachineState {
unify_fn: MachineState::unify,
bind_fn: MachineState::bind,
run_cleaners_fn: |_| false,
throwing_resource_error: false,
}
}

Expand Down
19 changes: 17 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<HeapCellValue>()
std::mem::size_of::<HeapCellValue>().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::<HeapCellValue>(),
usize::MAX,
)
})
}};
}

macro_rules! cell_index {
($idx:expr) => {
($idx) / std::mem::size_of::<HeapCellValue>()
Expand Down
Loading