Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/interpreter/src/instructions/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ macro_rules! resize_memory {
$crate::resize_memory!($interpreter, $offset, $len, ())
};
($interpreter:expr, $offset:expr, $len:expr, $ret:expr) => {
#[cfg(feature = "memory_limit")]
if $interpreter.memory.limit_reached($offset, $len) {
$interpreter.halt_memory_limit_oog();
return $ret;
}
if !$crate::interpreter::resize_memory(
&mut $interpreter.gas,
&mut $interpreter.memory,
Expand Down
82 changes: 82 additions & 0 deletions crates/interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ impl<IW: InterpreterTypes> Interpreter<IW> {
#[cold]
#[inline(never)]
pub fn halt_memory_oog(&mut self) {
self.halt(InstructionResult::MemoryOOG);
}

/// Halt the interpreter with an out-of-gas error.
#[cold]
#[inline(never)]
pub fn halt_memory_limit_oog(&mut self) {
self.halt(InstructionResult::MemoryLimitOOG);
}

Expand Down Expand Up @@ -431,3 +438,78 @@ mod tests {
);
}
}

#[test]
fn test_mstore_big_offset_memory_oog() {
use super::*;
use crate::{host::DummyHost, instructions::instruction_table};
use bytecode::Bytecode;
use primitives::Bytes;

let code = Bytes::from(
&[
0x60, 0x00, // PUSH1 0x00
0x61, 0x27, 0x10, // PUSH2 0x2710 (10,000)
0x52, // MSTORE
0x00, // STOP
][..],
);
let bytecode = Bytecode::new_raw(code);

let mut interpreter = Interpreter::<EthInterpreter>::new(
SharedMemory::new(),
ExtBytecode::new(bytecode),
InputsImpl::default(),
false,
SpecId::default(),
1000,
);

let table = instruction_table::<EthInterpreter, DummyHost>();
let mut host = DummyHost;
let action = interpreter.run_plain(&table, &mut host);

assert!(action.is_return());
assert_eq!(
action.instruction_result(),
Some(InstructionResult::MemoryOOG)
);
}

#[test]
#[cfg(feature = "memory_limit")]
fn test_mstore_big_offset_memory_limit_oog() {
use super::*;
use crate::{host::DummyHost, instructions::instruction_table};
use bytecode::Bytecode;
use primitives::Bytes;

let code = Bytes::from(
&[
0x60, 0x00, // PUSH1 0x00
0x61, 0x27, 0x10, // PUSH2 0x2710 (10,000)
0x52, // MSTORE
0x00, // STOP
][..],
);
let bytecode = Bytecode::new_raw(code);

let mut interpreter = Interpreter::<EthInterpreter>::new(
SharedMemory::new_with_memory_limit(1000),
ExtBytecode::new(bytecode),
InputsImpl::default(),
false,
SpecId::default(),
100000,
);

let table = instruction_table::<EthInterpreter, DummyHost>();
let mut host = DummyHost;
let action = interpreter.run_plain(&table, &mut host);

assert!(action.is_return());
assert_eq!(
action.instruction_result(),
Some(InstructionResult::MemoryLimitOOG)
);
}
19 changes: 11 additions & 8 deletions crates/interpreter/src/interpreter/shared_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ impl MemoryTr for SharedMemory {
self.resize(new_size);
true
}

/// Returns `true` if the `new_size` for the current context memory will
/// make the shared buffer length exceed the `memory_limit`.
#[cfg(feature = "memory_limit")]
#[inline]
fn limit_reached(&self, offset: usize, len: usize) -> bool {
self.my_checkpoint
.saturating_add(offset)
.saturating_add(len) as u64
> self.memory_limit
}
}

impl SharedMemory {
Expand Down Expand Up @@ -200,14 +211,6 @@ impl SharedMemory {
self.buffer().dbg_borrow_mut()
}

/// Returns `true` if the `new_size` for the current context memory will
/// make the shared buffer length exceed the `memory_limit`.
#[cfg(feature = "memory_limit")]
#[inline]
pub fn limit_reached(&self, new_size: usize) -> bool {
self.my_checkpoint.saturating_add(new_size) as u64 > self.memory_limit
}

/// Prepares the shared memory for a new child context.
///
/// # Panics
Expand Down
7 changes: 6 additions & 1 deletion crates/interpreter/src/interpreter_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,13 @@ pub trait MemoryTr {
///
/// # Note
///
/// It checks memory limits.
/// It checks if the memory allocation fits under gas cap.
fn resize(&mut self, new_size: usize) -> bool;

/// Returns `true` if the `new_size` for the current context memory will
/// make the shared buffer length exceed the `memory_limit`.
#[cfg(feature = "memory_limit")]
fn limit_reached(&self, offset: usize, len: usize) -> bool;
}

/// Functions needed for Interpreter Stack operations.
Expand Down
Loading