From 5c6e12b2c020d1b8b2981a8a81ae670a990d14b8 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 1 Feb 2023 08:28:05 +0100 Subject: [PATCH] Update existing and add new test cases. --- .../libyul/yulInterpreterTests/and_create.yul | 2 + .../yulInterpreterTests/and_create2.yul | 2 + .../external_call_to_self.yul | 1 + .../infinite_recursion_tracelimit.yul | 34 +++++++- .../yulInterpreterTests/pop_byte_shr_call.yul | 1 + .../yulInterpreterTests/zero_length_reads.yul | 40 +++++++++ .../zero_length_reads_and_revert.yul | 40 +++++++++ .../libyul/yulInterpreterTests/zero_range.yul | 1 + .../loadResolver/zero_length_reads.yul | 45 ++++++++++ .../EVMInstructionInterpreter.cpp | 84 +++++++------------ 10 files changed, 197 insertions(+), 53 deletions(-) create mode 100644 test/libyul/yulInterpreterTests/zero_length_reads.yul create mode 100644 test/libyul/yulInterpreterTests/zero_length_reads_and_revert.yul create mode 100644 test/libyul/yulOptimizerTests/loadResolver/zero_length_reads.yul diff --git a/test/libyul/yulInterpreterTests/and_create.yul b/test/libyul/yulInterpreterTests/and_create.yul index cbc68ca62..cf32c4658 100644 --- a/test/libyul/yulInterpreterTests/and_create.yul +++ b/test/libyul/yulInterpreterTests/and_create.yul @@ -6,6 +6,8 @@ } // ---- // Trace: +// CREATE(0, 0, 0) +// CREATE(0, 0, 0) // Memory dump: // 0: 0000000000000000000000000000000000000000000000000000000000000001 // Storage dump: diff --git a/test/libyul/yulInterpreterTests/and_create2.yul b/test/libyul/yulInterpreterTests/and_create2.yul index 0c0135500..5201b0188 100644 --- a/test/libyul/yulInterpreterTests/and_create2.yul +++ b/test/libyul/yulInterpreterTests/and_create2.yul @@ -8,6 +8,8 @@ // EVMVersion: >=constantinople // ---- // Trace: +// CREATE2(0, 0, 0, 0) +// CREATE2(0, 0, 0, 0) // Memory dump: // 0: 0000000000000000000000000000000000000000000000000000000000000001 // Storage dump: diff --git a/test/libyul/yulInterpreterTests/external_call_to_self.yul b/test/libyul/yulInterpreterTests/external_call_to_self.yul index 711159a9f..ad2d2bb77 100644 --- a/test/libyul/yulInterpreterTests/external_call_to_self.yul +++ b/test/libyul/yulInterpreterTests/external_call_to_self.yul @@ -14,6 +14,7 @@ // ---- // Trace: // CALL(153, 0x11111111, 0, 64, 32, 256, 32) +// RETURN(0, 0) // Memory dump: // 40: 0000000000000000000000000000000000000000000000000000000000000042 // 100: 0000000000000000000000000000000000000000000000000000000000000042 diff --git a/test/libyul/yulInterpreterTests/infinite_recursion_tracelimit.yul b/test/libyul/yulInterpreterTests/infinite_recursion_tracelimit.yul index 65c28ed5e..45d3cc781 100644 --- a/test/libyul/yulInterpreterTests/infinite_recursion_tracelimit.yul +++ b/test/libyul/yulInterpreterTests/infinite_recursion_tracelimit.yul @@ -7,6 +7,38 @@ } // ---- // Trace: -// Interpreter execution step limit reached. +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// LOG0(0, 0) +// Trace size limit reached. // Memory dump: // Storage dump: diff --git a/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul b/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul index 51e0602a3..4e431a6b1 100644 --- a/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul +++ b/test/libyul/yulInterpreterTests/pop_byte_shr_call.yul @@ -5,5 +5,6 @@ // EVMVersion: >=constantinople // ---- // Trace: +// CALL(0, 0, 0, 0, 0, 0, 0) // Memory dump: // Storage dump: diff --git a/test/libyul/yulInterpreterTests/zero_length_reads.yul b/test/libyul/yulInterpreterTests/zero_length_reads.yul new file mode 100644 index 000000000..6c1f38d1e --- /dev/null +++ b/test/libyul/yulInterpreterTests/zero_length_reads.yul @@ -0,0 +1,40 @@ +{ + returndatacopy(1, 1, 0) + calldatacopy(1, 1, 0) + extcodecopy(1, 1, 1, 0) + codecopy(1, 1, 0) + log0(1, 0) + log1(1, 0, 1) + log2(1, 0, 1, 1) + log3(1, 0, 1, 1, 1) + log4(1, 0, 1, 1, 1, 1) + pop(create(1, 1, 0)) + pop(create2(1, 1, 0, 1)) + pop(call(1, 1, 1, 1, 0, 1, 0)) + pop(callcode(1, 1, 1, 1, 0, 1, 0)) + pop(delegatecall(1, 1, 1, 0, 1, 0)) + pop(staticcall(1, 1, 1, 0, 1, 0)) + return(1, 0) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Trace: +// RETURNDATACOPY(0, 1, 0) +// CALLDATACOPY(0, 1, 0) +// EXTCODECOPY(1, 0, 1, 0) +// CODECOPY(0, 1, 0) +// LOG0(0, 0) +// LOG1(0, 0, 1) +// LOG2(0, 0, 1, 1) +// LOG3(0, 0, 1, 1, 1) +// LOG4(0, 0, 1, 1, 1, 1) +// CREATE(1, 0, 0) +// CREATE2(1, 0, 0, 1) +// CALL(1, 1, 1, 0, 0, 1, 0) +// CALLCODE(1, 1, 1, 0, 0, 1, 0) +// DELEGATECALL(1, 1, 0, 0, 1, 0) +// STATICCALL(1, 1, 0, 0, 1, 0) +// RETURN(0, 0) +// Memory dump: +// Storage dump: diff --git a/test/libyul/yulInterpreterTests/zero_length_reads_and_revert.yul b/test/libyul/yulInterpreterTests/zero_length_reads_and_revert.yul new file mode 100644 index 000000000..4be49eeb0 --- /dev/null +++ b/test/libyul/yulInterpreterTests/zero_length_reads_and_revert.yul @@ -0,0 +1,40 @@ +{ + returndatacopy(1, 1, 0) + calldatacopy(1, 1, 0) + extcodecopy(1, 1, 1, 0) + codecopy(1, 1, 0) + log0(1, 0) + log1(1, 0, 1) + log2(1, 0, 1, 1) + log3(1, 0, 1, 1, 1) + log4(1, 0, 1, 1, 1, 1) + pop(create(1, 1, 0)) + pop(create2(1, 1, 0, 1)) + pop(call(1, 1, 1, 1, 0, 1, 0)) + pop(callcode(1, 1, 1, 1, 0, 1, 0)) + pop(delegatecall(1, 1, 1, 0, 1, 0)) + pop(staticcall(1, 1, 1, 0, 1, 0)) + revert(1, 0) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Trace: +// RETURNDATACOPY(0, 1, 0) +// CALLDATACOPY(0, 1, 0) +// EXTCODECOPY(1, 0, 1, 0) +// CODECOPY(0, 1, 0) +// LOG0(0, 0) +// LOG1(0, 0, 1) +// LOG2(0, 0, 1, 1) +// LOG3(0, 0, 1, 1, 1) +// LOG4(0, 0, 1, 1, 1, 1) +// CREATE(1, 0, 0) +// CREATE2(1, 0, 0, 1) +// CALL(1, 1, 1, 0, 0, 1, 0) +// CALLCODE(1, 1, 1, 0, 0, 1, 0) +// DELEGATECALL(1, 1, 0, 0, 1, 0) +// STATICCALL(1, 1, 0, 0, 1, 0) +// REVERT(0, 0) +// Memory dump: +// Storage dump: diff --git a/test/libyul/yulInterpreterTests/zero_range.yul b/test/libyul/yulInterpreterTests/zero_range.yul index 5e1042dfb..1ad25ed37 100644 --- a/test/libyul/yulInterpreterTests/zero_range.yul +++ b/test/libyul/yulInterpreterTests/zero_range.yul @@ -5,5 +5,6 @@ } // ---- // Trace: +// CALLDATACOPY(0, 0, 0) // Memory dump: // Storage dump: diff --git a/test/libyul/yulOptimizerTests/loadResolver/zero_length_reads.yul b/test/libyul/yulOptimizerTests/loadResolver/zero_length_reads.yul new file mode 100644 index 000000000..418221a93 --- /dev/null +++ b/test/libyul/yulOptimizerTests/loadResolver/zero_length_reads.yul @@ -0,0 +1,45 @@ +{ + returndatacopy(1, 1, 0) + calldatacopy(1, 1, 0) + extcodecopy(1, 1, 1, 0) + codecopy(1, 1, 0) + log0(1, 0) + log1(1, 0, 1) + log2(1, 0, 1, 1) + log3(1, 0, 1, 1, 1) + log4(1, 0, 1, 1, 1, 1) + pop(create(1, 1, 0)) + pop(create2(1, 1, 0, 1)) + pop(call(1, 1, 1, 1, 0, 1, 0)) + pop(callcode(1, 1, 1, 1, 0, 1, 0)) + pop(delegatecall(1, 1, 1, 0, 1, 0)) + pop(staticcall(1, 1, 1, 0, 1, 0)) + return(1, 0) +} +// ==== +// EVMVersion: >=constantinople +// ---- +// step: loadResolver +// +// { +// { +// let _1 := 0 +// let _2 := 1 +// returndatacopy(0, _2, _1) +// calldatacopy(0, _2, _1) +// extcodecopy(_2, 0, _2, _1) +// codecopy(0, _2, _1) +// log0(0, _1) +// log1(0, _1, _2) +// log2(0, _1, _2, _2) +// log3(0, _1, _2, _2, _2) +// log4(0, _1, _2, _2, _2, _2) +// pop(create(_2, 0, _1)) +// pop(create2(_2, 0, _1, _2)) +// pop(call(_2, _2, _2, 0, _1, _2, _1)) +// pop(callcode(_2, _2, _2, 0, _1, _2, _1)) +// pop(delegatecall(_2, _2, 0, _1, _2, _1)) +// pop(staticcall(_2, _2, 0, _1, _2, _1)) +// return(0, _1) +// } +// } diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index ed73a4381..b049ee6c4 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -216,8 +216,7 @@ u256 EVMInstructionInterpreter::eval( m_state.memory, m_state.calldata, size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) ); - if (arg[2] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::CODESIZE: return m_state.code.size(); @@ -227,8 +226,7 @@ u256 EVMInstructionInterpreter::eval( m_state.memory, m_state.code, size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) ); - if (arg[2] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::GASPRICE: return m_state.gasprice; @@ -247,8 +245,7 @@ u256 EVMInstructionInterpreter::eval( m_state.memory, m_state.code, size_t(arg[1]), size_t(arg[2]), size_t(arg[3]) ); - if (arg[3] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::RETURNDATASIZE: return m_state.returndata.size(); @@ -258,8 +255,7 @@ u256 EVMInstructionInterpreter::eval( m_state.memory, m_state.returndata, size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) ); - if (arg[2] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::BLOCKHASH: if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber) @@ -301,54 +297,44 @@ u256 EVMInstructionInterpreter::eval( return 0x99; case Instruction::LOG0: accessMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::LOG1: accessMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::LOG2: accessMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::LOG3: accessMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; case Instruction::LOG4: accessMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); return 0; // --------------- calls --------------- case Instruction::CREATE: accessMemory(arg[1], arg[2]); + logTrace(_instruction, arg); if (arg[2] != 0) - { - logTrace(_instruction, arg); return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); - } - return 0xcccccc; + else + return 0xcccccc; case Instruction::CREATE2: accessMemory(arg[1], arg[2]); + logTrace(_instruction, arg); if (arg[2] != 0) - { - logTrace(_instruction, arg); return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); - } - return 0xdddddd; + else + return 0xdddddd; case Instruction::CALL: case Instruction::CALLCODE: - if (arg[4] != 0) - accessMemory(arg[3], arg[4]); - if (arg[6] != 0) - accessMemory(arg[5], arg[6]); - if (arg[4] != 0 && arg[6] != 0) - logTrace(_instruction, arg); + accessMemory(arg[3], arg[4]); + accessMemory(arg[5], arg[6]); + logTrace(_instruction, arg); // Randomly fail based on the called address if it isn't a call to self. // Used for fuzzing. return ( @@ -357,12 +343,9 @@ u256 EVMInstructionInterpreter::eval( ) ? 1 : 0; case Instruction::DELEGATECALL: case Instruction::STATICCALL: - if (arg[3] != 0) - accessMemory(arg[2], arg[3]); - if (arg[5] != 0) - accessMemory(arg[4], arg[5]); - if (arg[3] != 0 && arg[5] != 0) - logTrace(_instruction, arg); + accessMemory(arg[2], arg[3]); + accessMemory(arg[4], arg[5]); + logTrace(_instruction, arg); // Randomly fail based on the called address if it isn't a call to self. // Used for fuzzing. return ( @@ -374,16 +357,13 @@ u256 EVMInstructionInterpreter::eval( m_state.returndata = {}; if (accessMemory(arg[0], arg[1])) m_state.returndata = m_state.readMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg, m_state.returndata); + logTrace(_instruction, arg, m_state.returndata); BOOST_THROW_EXCEPTION(ExplicitlyTerminatedWithReturn()); } case Instruction::REVERT: accessMemory(arg[0], arg[1]); - if (arg[1] != 0) - logTrace(_instruction, arg); + logTrace(_instruction, arg); m_state.storage.clear(); - m_state.trace.clear(); BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); case Instruction::INVALID: logTrace(_instruction); @@ -611,7 +591,7 @@ std::pair EVMInstructionInterpreter::isInputMemoryPtrModified( std::vector const& _arguments ) { - if (_pseudoInstruction == "return" || _pseudoInstruction == "revert") + if (_pseudoInstruction == "RETURN" || _pseudoInstruction == "REVERT") { if (_arguments[1] == 0) return {true, 0}; @@ -619,15 +599,15 @@ std::pair EVMInstructionInterpreter::isInputMemoryPtrModified( return {false, 0}; } else if ( - _pseudoInstruction == "returndatacopy" || _pseudoInstruction == "calldatacopy" - || _pseudoInstruction == "codecopy") + _pseudoInstruction == "RETURNDATACOPY" || _pseudoInstruction == "CALLDATACOPY" + || _pseudoInstruction == "CODECOPY") { if (_arguments[2] == 0) return {true, 0}; else return {false, 0}; } - else if (_pseudoInstruction == "extcodedatacopy") + else if (_pseudoInstruction == "EXTCODECOPY") { if (_arguments[3] == 0) return {true, 1}; @@ -635,29 +615,29 @@ std::pair EVMInstructionInterpreter::isInputMemoryPtrModified( return {false, 0}; } else if ( - _pseudoInstruction == "log0" || _pseudoInstruction == "log1" || _pseudoInstruction == "log2" - || _pseudoInstruction == "log3" || _pseudoInstruction == "log4") + _pseudoInstruction == "LOG0" || _pseudoInstruction == "LOG1" || _pseudoInstruction == "LOG2" + || _pseudoInstruction == "LOG3" || _pseudoInstruction == "LOG4") { if (_arguments[1] == 0) return {true, 0}; else return {false, 0}; } - if (_pseudoInstruction == "create" || _pseudoInstruction == "create2") + if (_pseudoInstruction == "CREATE" || _pseudoInstruction == "CREATE2") { if (_arguments[2] == 0) return {true, 1}; else return {false, 0}; } - if (_pseudoInstruction == "call" || _pseudoInstruction == "callcode") + if (_pseudoInstruction == "CALL" || _pseudoInstruction == "CALLCODE") { if (_arguments[4] == 0) return {true, 3}; else return {false, 0}; } - else if (_pseudoInstruction == "delegatecall" || _pseudoInstruction == "staticcall") + else if (_pseudoInstruction == "DELEGATECALL" || _pseudoInstruction == "STATICCALL") { if (_arguments[3] == 0) return {true, 2};