Skip to content

Commit 0bc7068

Browse files
arajasekvyzo
andauthored
chore: backport #1188 (#1200)
check all instructions for stack underflow behaviour none should panic. Co-authored-by: vyzo <[email protected]>
1 parent 6c151fa commit 0bc7068

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

actors/evm/src/interpreter/execution.rs

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,231 @@ pub fn execute(
284284
) -> Result<Output, ActorError> {
285285
Machine::new(system, runtime, bytecode).execute()
286286
}
287+
288+
#[cfg(test)]
289+
mod tests {
290+
use crate::evm_unit_test;
291+
292+
macro_rules! check_underflow_err {
293+
($($ins:ident,)*) => {
294+
$(do_check_underflow_err!($ins);)*
295+
}
296+
}
297+
298+
macro_rules! check_underflow_none {
299+
($($ins:ident,)*) => {
300+
$(do_check_underflow_none!($ins);)*
301+
}
302+
}
303+
304+
macro_rules! do_check_underflow_err {
305+
($ins:ident) => {
306+
{
307+
evm_unit_test! {
308+
(m) { $ins; }
309+
let result = m.step();
310+
assert!(result.is_err(), stringify!($ins));
311+
assert_eq!(result.unwrap_err().exit_code(), crate::EVM_CONTRACT_STACK_UNDERFLOW, stringify!($ins));
312+
};
313+
}
314+
}
315+
}
316+
317+
macro_rules! do_check_underflow_none {
318+
($ins:ident) => {{
319+
evm_unit_test! {
320+
(m) { $ins; }
321+
let result = m.step();
322+
assert!(result.is_ok(), stringify!($ins));
323+
};
324+
}};
325+
}
326+
327+
#[test]
328+
fn test_execution_underflow() {
329+
check_underflow_err!(
330+
ADD,
331+
MUL,
332+
SUB,
333+
DIV,
334+
SDIV,
335+
MOD,
336+
SMOD,
337+
ADDMOD,
338+
MULMOD,
339+
EXP,
340+
SIGNEXTEND,
341+
LT,
342+
GT,
343+
SLT,
344+
SGT,
345+
EQ,
346+
ISZERO,
347+
AND,
348+
OR,
349+
XOR,
350+
NOT,
351+
BYTE,
352+
SHL,
353+
SHR,
354+
SAR,
355+
DUP1,
356+
DUP2,
357+
DUP3,
358+
DUP4,
359+
DUP5,
360+
DUP6,
361+
DUP7,
362+
DUP8,
363+
DUP9,
364+
DUP10,
365+
DUP11,
366+
DUP12,
367+
DUP13,
368+
DUP14,
369+
DUP15,
370+
DUP16,
371+
SWAP1,
372+
SWAP2,
373+
SWAP3,
374+
SWAP4,
375+
SWAP5,
376+
SWAP6,
377+
SWAP7,
378+
SWAP8,
379+
SWAP9,
380+
SWAP10,
381+
SWAP11,
382+
SWAP12,
383+
SWAP13,
384+
SWAP14,
385+
SWAP15,
386+
SWAP16,
387+
POP,
388+
KECCAK256,
389+
BALANCE,
390+
CALLDATALOAD,
391+
CALLDATACOPY,
392+
EXTCODESIZE,
393+
EXTCODECOPY,
394+
EXTCODEHASH,
395+
RETURNDATACOPY,
396+
BLOCKHASH,
397+
MLOAD,
398+
MSTORE,
399+
MSTORE8,
400+
SLOAD,
401+
SSTORE,
402+
LOG0,
403+
LOG1,
404+
LOG2,
405+
LOG3,
406+
LOG4,
407+
CALL,
408+
DELEGATECALL,
409+
STATICCALL,
410+
CODECOPY,
411+
CREATE,
412+
CREATE2,
413+
RETURN,
414+
REVERT,
415+
SELFDESTRUCT,
416+
JUMP,
417+
JUMPI,
418+
);
419+
420+
check_underflow_none!(
421+
PUSH0,
422+
PUSH1,
423+
PUSH2,
424+
PUSH3,
425+
PUSH4,
426+
PUSH5,
427+
PUSH6,
428+
PUSH7,
429+
PUSH8,
430+
PUSH9,
431+
PUSH10,
432+
PUSH11,
433+
PUSH12,
434+
PUSH13,
435+
PUSH14,
436+
PUSH15,
437+
PUSH16,
438+
PUSH17,
439+
PUSH18,
440+
PUSH19,
441+
PUSH20,
442+
PUSH21,
443+
PUSH22,
444+
PUSH23,
445+
PUSH24,
446+
PUSH25,
447+
PUSH26,
448+
PUSH27,
449+
PUSH28,
450+
PUSH29,
451+
PUSH30,
452+
PUSH31,
453+
PUSH32,
454+
ADDRESS,
455+
ORIGIN,
456+
CALLER,
457+
CALLVALUE,
458+
CALLDATASIZE,
459+
GASPRICE,
460+
RETURNDATASIZE,
461+
COINBASE,
462+
TIMESTAMP,
463+
NUMBER,
464+
GASLIMIT,
465+
CHAINID,
466+
BASEFEE,
467+
SELFBALANCE,
468+
MSIZE,
469+
CODESIZE,
470+
JUMPDEST,
471+
STOP,
472+
PC,
473+
);
474+
475+
// manual checks
476+
{
477+
evm_unit_test! {
478+
(rt) {
479+
let epoch = 1234;
480+
rt.set_epoch(epoch);
481+
rt.expect_get_randomness_from_beacon(
482+
fil_actors_runtime::runtime::DomainSeparationTag::EvmPrevRandao,
483+
epoch,
484+
Vec::from(*b"prevrandao"),
485+
[0xff; 32]
486+
);
487+
}
488+
(m) { PREVRANDAO; }
489+
let result = m.step();
490+
assert!(result.is_ok());
491+
};
492+
}
493+
494+
{
495+
evm_unit_test! {
496+
(rt) {
497+
rt.expect_gas_available(1234);
498+
}
499+
(m) { GAS; }
500+
let result = m.step();
501+
assert!(result.is_ok());
502+
};
503+
}
504+
505+
{
506+
evm_unit_test! {
507+
(m) { INVALID; }
508+
let result = m.step();
509+
assert!(result.is_err());
510+
assert_eq!(result.unwrap_err().exit_code(), crate::EVM_CONTRACT_INVALID_INSTRUCTION);
511+
};
512+
}
513+
}
514+
}

actors/evm/src/interpreter/test_util.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ macro_rules! evm_unit_test {
5353
use $crate::{Bytecode, EthAddress, ExecutionState};
5454

5555
let mut rt = MockRuntime::default();
56+
rt.in_call = true;
5657
let mut state = ExecutionState::new(
5758
EthAddress::from_id(1000),
5859
EthAddress::from_id(1000),

0 commit comments

Comments
 (0)