@@ -694,6 +694,14 @@ tests! {
694694 exp4( op:: EXP , 2_ U256 , 2_ U256 => 4_ U256 ; op_gas( 60 ) ) ,
695695 exp5( op:: EXP , 2_ U256 , 3_ U256 => 8_ U256 ; op_gas( 60 ) ) ,
696696 exp6( op:: EXP , 2_ U256 , 4_ U256 => 16_ U256 ; op_gas( 60 ) ) ,
697+ exp_zero_base_zero_exp( op:: EXP , 0_ U256 , 0_ U256 => 1_ U256 ; op_gas( 10 ) ) ,
698+ exp_zero_base_nonzero_exp( op:: EXP , 0_ U256 , 5_ U256 => 0_ U256 ; op_gas( 60 ) ) ,
699+ exp_one_base_large_exp( op:: EXP , 1_ U256 , U256 :: MAX => 1_ U256 ; op_gas( 1610 ) ) ,
700+ exp_minus_one_base_even_exp( op:: EXP , -1_ U256 , 4_ U256 => 1_ U256 ; op_gas( 60 ) ) ,
701+ exp_minus_one_base_odd_exp( op:: EXP , -1_ U256 , 5_ U256 => -1_ U256 ; op_gas( 60 ) ) ,
702+ exp_pow4_base_in_range( op:: EXP , 4_ U256 , 63_ U256 => 1_ U256 << 126 ; op_gas( 60 ) ) ,
703+ exp_pow4_base_overflow( op:: EXP , 4_ U256 , 128_ U256 => 0_ U256 ; op_gas( 60 ) ) ,
704+ exp_non_pow2_base( op:: EXP , 3_ U256 , 5_ U256 => 243_ U256 ; op_gas( 60 ) ) ,
697705 exp_overflow( op:: EXP , 2_ U256 , 256_ U256 => 0_ U256 ; op_gas( 110 ) ) ,
698706 // Large exponent spanning multiple bytes.
699707 exp_large( op:: EXP , 2_ U256 , 0xFFFF_ U256 => 2_ U256 . pow( 0xFFFF_ U256 ) ; op_gas( 110 ) ) ,
@@ -815,6 +823,12 @@ tests! {
815823 expected_stack: & [ KECCAK_EMPTY . into( ) ] ,
816824 expected_gas: 2 + 3 + gas:: KECCAK256 ,
817825 } ) ,
826+ keccak256_empty_dynamic_offset( @raw {
827+ bytecode: & [ op:: ADDRESS , op:: PUSH0 , op:: KECCAK256 ] ,
828+ expected_return: InstructionResult :: InvalidOperandOOG ,
829+ expected_stack: STACK_WHAT_INTERPRETER_SAYS ,
830+ expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
831+ } ) ,
818832 keccak256_1( @raw {
819833 bytecode: & [ op:: PUSH1 , 32 , op:: PUSH0 , op:: KECCAK256 ] ,
820834 expected_stack: & [ keccak256( [ 0 ; 32 ] ) . into( ) ] ,
@@ -1073,11 +1087,38 @@ tests! {
10731087 expected_stack: & [ DEF_ADDR . into_word( ) . into( ) ] ,
10741088 expected_gas: 5 ,
10751089 } ) ,
1090+ mload_const_offset_too_large( @raw {
1091+ bytecode: & {
1092+ let mut code = Vec :: new( ) ;
1093+ code. push( op:: PUSH9 ) ;
1094+ code. extend_from_slice( & 0x1_0000_0000_0000_0000_ U256 . to_be_bytes:: <32 >( ) [ 23 ..] ) ;
1095+ code. push( op:: MLOAD ) ;
1096+ code
1097+ } ,
1098+ expected_return: InstructionResult :: InvalidOperandOOG ,
1099+ expected_stack: & [ 0x1_0000_0000_0000_0000_ U256 ] ,
1100+ expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
1101+ } ) ,
10761102 mstore1( @raw {
10771103 bytecode: & [ op:: PUSH0 , op:: PUSH0 , op:: MSTORE ] ,
10781104 expected_memory: & [ 0 ; 32 ] ,
10791105 expected_gas: 2 + 2 + ( 3 + memory_gas_cost( 1 ) ) ,
10801106 } ) ,
1107+ mstore_const_offset_dyn_value( @raw {
1108+ bytecode: & bytecode_binop_mixed( op:: MSTORE , 0_ U256 , 0x69_ U256 , true , false ) ,
1109+ expected_memory: MEMORY_WHAT_INTERPRETER_SAYS ,
1110+ expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
1111+ } ) ,
1112+ mstore_dyn_offset_const_value( @raw {
1113+ bytecode: & bytecode_binop_mixed( op:: MSTORE , 0_ U256 , 0x69_ U256 , false , true ) ,
1114+ expected_memory: MEMORY_WHAT_INTERPRETER_SAYS ,
1115+ expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
1116+ } ) ,
1117+ mstore_dyn_offset_dyn_value( @raw {
1118+ bytecode: & bytecode_binop_mixed( op:: MSTORE , 0_ U256 , 0x69_ U256 , false , false ) ,
1119+ expected_memory: MEMORY_WHAT_INTERPRETER_SAYS ,
1120+ expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
1121+ } ) ,
10811122 mstore8_1( @raw {
10821123 bytecode: & [ op:: PUSH0 , op:: PUSH0 , op:: MSTORE8 ] ,
10831124 expected_memory: & [ 0 ; 32 ] ,
@@ -1330,6 +1371,12 @@ tests! {
13301371 expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
13311372 expected_next_action: ACTION_WHAT_INTERPRETER_SAYS ,
13321373 } ) ,
1374+ ret_empty_dynamic_offset( @raw {
1375+ bytecode: & [ op:: ADDRESS , op:: PUSH0 , op:: RETURN ] ,
1376+ expected_return: InstructionResult :: InvalidOperandOOG ,
1377+ expected_stack: STACK_WHAT_INTERPRETER_SAYS ,
1378+ expected_gas: GAS_WHAT_INTERPRETER_SAYS ,
1379+ } ) ,
13331380 ret( @raw {
13341381 bytecode: & [ op:: PUSH1 , 0x69 , op:: PUSH0 , op:: MSTORE , op:: PUSH1 , 32 , op:: PUSH0 , op:: RETURN ] ,
13351382 expected_return: InstructionResult :: Return ,
@@ -2078,48 +2125,55 @@ fn bytecode_unop_opaque(opcode: u8, a: U256) -> Vec<u8> {
20782125 code
20792126}
20802127
2081- /// Build bytecode: MSTORE(a, 0), MSTORE(b, 32), MLOAD(32), MLOAD(0), `<op>`
2082- ///
2083- /// The operands pass through MLOAD (an opaque builtin), preventing the compiler
2084- /// from constant-folding or exploiting UB at compile time.
2085- fn bytecode_binop_opaque ( opcode : u8 , a : U256 , b : U256 ) -> Vec < u8 > {
2128+ fn push_const_or_load ( code : & mut Vec < u8 > , value : U256 , is_const : bool , offset : u8 ) {
2129+ if is_const {
2130+ code. push ( op:: PUSH32 ) ;
2131+ code. extend_from_slice ( & value. to_be_bytes :: < 32 > ( ) ) ;
2132+ } else {
2133+ code. push ( op:: PUSH1 ) ;
2134+ code. push ( offset) ;
2135+ code. push ( op:: MLOAD ) ;
2136+ }
2137+ }
2138+
2139+ fn store_dynamic_operands ( code : & mut Vec < u8 > , operands : & [ ( U256 , bool , u8 ) ] ) {
2140+ for & ( value, is_const, offset) in operands {
2141+ if !is_const {
2142+ code. push ( op:: PUSH32 ) ;
2143+ code. extend_from_slice ( & value. to_be_bytes :: < 32 > ( ) ) ;
2144+ code. push ( op:: PUSH1 ) ;
2145+ code. push ( offset) ;
2146+ code. push ( op:: MSTORE ) ;
2147+ }
2148+ }
2149+ }
2150+
2151+ fn bytecode_binop_mixed ( opcode : u8 , a : U256 , b : U256 , a_const : bool , b_const : bool ) -> Vec < u8 > {
20862152 let mut code = Vec :: with_capacity ( 128 ) ;
2087- code. push ( op:: PUSH32 ) ;
2088- code. extend_from_slice ( & a. to_be_bytes :: < 32 > ( ) ) ;
2089- code. push ( op:: PUSH1 ) ;
2090- code. push ( 0x00 ) ;
2091- code. push ( op:: MSTORE ) ;
2092- code. push ( op:: PUSH32 ) ;
2093- code. extend_from_slice ( & b. to_be_bytes :: < 32 > ( ) ) ;
2094- code. push ( op:: PUSH1 ) ;
2095- code. push ( 0x20 ) ;
2096- code. push ( op:: MSTORE ) ;
2097- code. push ( op:: PUSH1 ) ;
2098- code. push ( 0x20 ) ;
2099- code. push ( op:: MLOAD ) ;
2100- code. push ( op:: PUSH1 ) ;
2101- code. push ( 0x00 ) ;
2102- code. push ( op:: MLOAD ) ;
2153+ store_dynamic_operands ( & mut code, & [ ( a, a_const, 0x00 ) , ( b, b_const, 0x20 ) ] ) ;
2154+ push_const_or_load ( & mut code, b, b_const, 0x20 ) ;
2155+ push_const_or_load ( & mut code, a, a_const, 0x00 ) ;
21032156 code. push ( opcode) ;
21042157 code
21052158}
21062159
2107- /// Build opaque ternop bytecode: MSTORE(a,0), MSTORE(b,32), MSTORE(c,64),
2108- /// MLOAD(64), MLOAD(32), MLOAD(0), `<op>`.
2109- fn bytecode_ternop_opaque ( opcode : u8 , a : U256 , b : U256 , c : U256 ) -> Vec < u8 > {
2160+ fn bytecode_ternop_mixed (
2161+ opcode : u8 ,
2162+ a : U256 ,
2163+ b : U256 ,
2164+ c : U256 ,
2165+ a_const : bool ,
2166+ b_const : bool ,
2167+ c_const : bool ,
2168+ ) -> Vec < u8 > {
21102169 let mut code = Vec :: with_capacity ( 192 ) ;
2111- for ( val, offset) in [ ( a, 0u8 ) , ( b, 0x20 ) , ( c, 0x40 ) ] {
2112- code. push ( op:: PUSH32 ) ;
2113- code. extend_from_slice ( & val. to_be_bytes :: < 32 > ( ) ) ;
2114- code. push ( op:: PUSH1 ) ;
2115- code. push ( offset) ;
2116- code. push ( op:: MSTORE ) ;
2117- }
2118- for offset in [ 0x40u8 , 0x20 , 0x00 ] {
2119- code. push ( op:: PUSH1 ) ;
2120- code. push ( offset) ;
2121- code. push ( op:: MLOAD ) ;
2122- }
2170+ store_dynamic_operands (
2171+ & mut code,
2172+ & [ ( a, a_const, 0x00 ) , ( b, b_const, 0x20 ) , ( c, c_const, 0x40 ) ] ,
2173+ ) ;
2174+ push_const_or_load ( & mut code, c, c_const, 0x40 ) ;
2175+ push_const_or_load ( & mut code, b, b_const, 0x20 ) ;
2176+ push_const_or_load ( & mut code, a, a_const, 0x00 ) ;
21232177 code. push ( opcode) ;
21242178 code
21252179}
0 commit comments