diff --git a/evm/src/cpu/kernel/asm/core/exception.asm b/evm/src/cpu/kernel/asm/core/exception.asm index 7d5c7d9c..70e8550b 100644 --- a/evm/src/cpu/kernel/asm/core/exception.asm +++ b/evm/src/cpu/kernel/asm/core/exception.asm @@ -155,8 +155,8 @@ min_stack_len_for_opcode: BYTES 2 // 0x05, SDIV BYTES 2 // 0x06, MOD BYTES 2 // 0x07, SMOD - BYTES 2 // 0x08, ADDMOD - BYTES 2 // 0x09, MULMOD + BYTES 3 // 0x08, ADDMOD + BYTES 3 // 0x09, MULMOD BYTES 2 // 0x0a, EXP BYTES 2 // 0x0b, SIGNEXTEND %rep 4 // 0x0c-0x0f, invalid @@ -222,7 +222,7 @@ min_stack_len_for_opcode: BYTES 1 // 0x54, SLOAD BYTES 2 // 0x55, SSTORE BYTES 1 // 0x56, JUMP - BYTES 1 // 0x57, JUMPI + BYTES 2 // 0x57, JUMPI BYTES 0 // 0x58, PC BYTES 0 // 0x59, MSIZE BYTES 0 // 0x5a, GAS diff --git a/evm/src/witness/errors.rs b/evm/src/witness/errors.rs index e28e7d0f..81d5ff01 100644 --- a/evm/src/witness/errors.rs +++ b/evm/src/witness/errors.rs @@ -11,6 +11,7 @@ pub enum ProgramError { StackOverflow, KernelPanic, MemoryError(MemoryError), + GasLimitError, } #[allow(clippy::enum_variant_names)] diff --git a/evm/src/witness/operation.rs b/evm/src/witness/operation.rs index 4cd725bb..94cf49ea 100644 --- a/evm/src/witness/operation.rs +++ b/evm/src/witness/operation.rs @@ -502,7 +502,7 @@ pub(crate) fn generate_syscall( mut row: CpuColumnsView, ) -> Result<(), ProgramError> { if TryInto::::try_into(state.registers.gas_used).is_err() { - panic!(); + return Err(ProgramError::GasLimitError); } if state.registers.stack_len < stack_values_read { @@ -544,13 +544,18 @@ pub(crate) fn generate_syscall( let syscall_info = U256::from(state.registers.program_counter + 1) + (U256::from(u64::from(state.registers.is_kernel)) << 32) + (U256::from(state.registers.gas_used) << 192); - let log_out = stack_push_log_and_fill(state, &mut row, syscall_info)?; + // Set registers before pushing to the stack; in particular, we need to set kernel mode so we + // can't incorrectly trigger a stack overflow. However, note that we have to do it _after_ we + // make `syscall_info`, which should contain the old values. state.registers.program_counter = new_program_counter; - log::debug!("Syscall to {}", KERNEL.offset_name(new_program_counter)); state.registers.is_kernel = true; state.registers.gas_used = 0; + let log_out = stack_push_log_and_fill(state, &mut row, syscall_info)?; + + log::debug!("Syscall to {}", KERNEL.offset_name(new_program_counter)); + state.traces.push_memory(log_in0); state.traces.push_memory(log_in1); state.traces.push_memory(log_in2); @@ -680,7 +685,7 @@ pub(crate) fn generate_exception( mut row: CpuColumnsView, ) -> Result<(), ProgramError> { if TryInto::::try_into(state.registers.gas_used).is_err() { - panic!(); + return Err(ProgramError::GasLimitError); } row.stack_len_bounds_aux = (row.stack_len + F::ONE).inverse(); @@ -719,13 +724,18 @@ pub(crate) fn generate_exception( let exc_info = U256::from(state.registers.program_counter) + (U256::from(state.registers.gas_used) << 192); - let log_out = stack_push_log_and_fill(state, &mut row, exc_info)?; + // Set registers before pushing to the stack; in particular, we need to set kernel mode so we + // can't incorrectly trigger a stack overflow. However, note that we have to do it _after_ we + // make `exc_info`, which should contain the old values. state.registers.program_counter = new_program_counter; - log::debug!("Exception to {}", KERNEL.offset_name(new_program_counter)); state.registers.is_kernel = true; state.registers.gas_used = 0; + let log_out = stack_push_log_and_fill(state, &mut row, exc_info)?; + + log::debug!("Exception to {}", KERNEL.offset_name(new_program_counter)); + state.traces.push_memory(log_in0); state.traces.push_memory(log_in1); state.traces.push_memory(log_in2);