Skip to content

Commit

Permalink
Add test for rounded overflows
Browse files Browse the repository at this point in the history
  • Loading branch information
LuisPH3 committed Oct 1, 2024
1 parent 691533b commit 2fd90bf
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 28 deletions.
13 changes: 7 additions & 6 deletions go/interpreter/lfvm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,13 @@ func opExtCodeCopy(c *context) error {
return err
}

var uint64CodeOffset uint64
if codeOffset.IsUint64() {
uint64CodeOffset = codeOffset.Uint64()
} else {
uint64CodeOffset = math.MaxUint64
}

// Charge for length of copied code
words := tosca.SizeInWords(length.Uint64())
if err := c.useGas(tosca.Gas(3 * words)); err != nil {
Expand All @@ -1002,12 +1009,6 @@ func opExtCodeCopy(c *context) error {
return err
}
}
var uint64CodeOffset uint64
if codeOffset.IsUint64() {
uint64CodeOffset = codeOffset.Uint64()
} else {
uint64CodeOffset = math.MaxUint64
}

data, err := c.memory.getSlice(memOffset.Uint64(), length.Uint64(), c)
if err != nil {
Expand Down
103 changes: 81 additions & 22 deletions go/interpreter/lfvm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1390,82 +1390,77 @@ func TestInstructions_InstructionsReturnErrorOnOverflow(t *testing.T) {
zero := *uint256.NewInt(0)
maxUint256 := *uint256.NewInt(0).Sub(uint256.NewInt(0), uint256.NewInt(1))

type inputData []uint256.Int
stack := func(v ...uint256.Int) inputData {
return append([]uint256.Int{}, v...)
}

tests := map[OpCode]struct {
implementation func(*context) error
inputs []inputData
}{
JUMP: {
implementation: opJump,
inputs: []inputData{
stack(maxUint256),
inputStack(maxUint256),
},
},
JUMPI: {
implementation: opJumpi,
inputs: []inputData{
stack(one, maxUint256),
inputStack(one, maxUint256),
},
},
MSTORE: {
implementation: opMstore,
inputs: []inputData{
stack(zero, maxUint256),
inputStack(zero, maxUint256),
},
},
MSTORE8: {
implementation: opMstore8,
inputs: []inputData{
stack(zero, maxUint256),
inputStack(zero, maxUint256),
},
},
MCOPY: {
implementation: opMcopy,
inputs: []inputData{
stack(maxUint256, zero, zero),
inputStack(maxUint256, zero, zero),
},
},
MLOAD: {
implementation: opMload,
inputs: []inputData{
stack(maxUint256),
inputStack(maxUint256),
},
},
CALLDATACOPY: {
implementation: opCallDataCopy,
inputs: []inputData{
stack(maxUint256, zero, zero),
stack(one, one, maxUint256),
inputStack(maxUint256, zero, zero),
inputStack(one, one, maxUint256),
},
},
RETURNDATACOPY: {
implementation: opReturnDataCopy,
inputs: []inputData{
stack(maxUint256, zero, zero),
stack(zero, maxUint256, zero),
stack(one, zero, maxUint256),
inputStack(maxUint256, zero, zero),
inputStack(zero, maxUint256, zero),
inputStack(one, zero, maxUint256),
},
},
CODECOPY: {
implementation: opCodeCopy,
inputs: []inputData{
stack(maxUint256, zero, zero),
inputStack(maxUint256, zero, zero),
},
},
EXTCODECOPY: {
implementation: opExtCodeCopy,
inputs: []inputData{
stack(maxUint256, zero, zero, zero),
inputStack(maxUint256, zero, zero, zero),
},
},
SHA3: {
implementation: opSha3,
inputs: []inputData{
stack(maxUint256, zero),
inputStack(maxUint256, zero),
},
},
// Note: Log0 tests stack values overflowing for all LOG operations
Expand All @@ -1474,16 +1469,16 @@ func TestInstructions_InstructionsReturnErrorOnOverflow(t *testing.T) {
return opLog(c, 0)
},
inputs: []inputData{
stack(maxUint256, one),
inputStack(maxUint256, one),
},
},
// Note: call operations are quite complicated and they are to be tested
// on its own means. This is just a simple test to validate the test itself.
CALL: {
implementation: opCall,
inputs: []inputData{
stack(maxUint256, one, zero, zero, zero, zero, zero),
stack(zero, zero, maxUint256, one, zero, zero, zero),
inputStack(maxUint256, one, zero, zero, zero, zero, zero),
inputStack(zero, zero, maxUint256, one, zero, zero, zero),
},
},
}
Expand Down Expand Up @@ -1511,3 +1506,67 @@ func TestInstructions_InstructionsReturnErrorOnOverflow(t *testing.T) {
})
}
}

func TestInstructions_CopyOpRoundStackValuesOnOverflow(t *testing.T) {
one := *uint256.NewInt(1)
zero := *uint256.NewInt(0)
maxUint256 := *uint256.NewInt(0).Sub(uint256.NewInt(0), uint256.NewInt(1))

tests := map[OpCode]struct {
implementation func(*context) error
inputs []inputData
}{
CALLDATACOPY: {
implementation: opCallDataCopy,
inputs: []inputData{
inputStack(zero, maxUint256, zero),
inputStack(zero, one, maxUint256),
},
},
CODECOPY: {
implementation: opCodeCopy,
inputs: []inputData{
inputStack(zero, maxUint256, zero),
},
},
EXTCODECOPY: {
implementation: opExtCodeCopy,
inputs: []inputData{
inputStack(zero, maxUint256, zero, one),
},
},
}

ctrl := gomock.NewController(t)
runContext := tosca.NewMockRunContext(ctrl)
runContext.EXPECT().GetCode(gomock.Any()).AnyTimes()

for op, test := range tests {
t.Run(op.String(), func(t *testing.T) {
for _, input := range test.inputs {
ctxt := getEmptyContext()
ctxt.context = runContext
ctxt.code = Code{{op, 0}}
ctxt.gas = 1 << 32

for _, v := range input {
ctxt.stack.push(&v)
}

err := test.implementation(&ctxt)
if err == errOverflow {
t.Fatalf("unexpected overflow")
}
}
})
}
}

////////////////////////////////////////////////////////////////////////////////
// Helper functions

type inputData []uint256.Int

func inputStack(v ...uint256.Int) inputData {
return append([]uint256.Int{}, v...)
}

0 comments on commit 2fd90bf

Please sign in to comment.