Skip to content

Commit

Permalink
♻️ Add out-of-gas revert if dataSize exceeds 2 bytes for SSTORE2 (#563)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized authored Aug 29, 2023
1 parent 9eea5e5 commit 58a0d26
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 20 deletions.
41 changes: 21 additions & 20 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -804,28 +804,29 @@ RedBlackTreeLibTest:testRedBlackTreeRemoveViaPointer() (gas: 58199)
RedBlackTreeLibTest:testRedBlackTreeTreeFullReverts() (gas: 50293)
RedBlackTreeLibTest:testRedBlackTreeTryInsertAndRemove() (gas: 56127)
RedBlackTreeLibTest:test__codesize() (gas: 13237)
SSTORE2Test:testReadInvalidPointerCustomBoundsReverts() (gas: 3197)
SSTORE2Test:testReadInvalidPointerCustomBoundsReverts(address,uint256,uint256) (runs: 256, μ: 723531, ~: 642314)
SSTORE2Test:testReadInvalidPointerCustomBoundsReverts() (gas: 3242)
SSTORE2Test:testReadInvalidPointerCustomBoundsReverts(address,uint256,uint256) (runs: 256, μ: 722753, ~: 637746)
SSTORE2Test:testReadInvalidPointerCustomStartBoundReverts() (gas: 3241)
SSTORE2Test:testReadInvalidPointerCustomStartBoundReverts(address,uint256) (runs: 256, μ: 722026, ~: 642645)
SSTORE2Test:testReadInvalidPointerRevert(address) (runs: 256, μ: 701190, ~: 642335)
SSTORE2Test:testReadInvalidPointerCustomStartBoundReverts(address,uint256) (runs: 256, μ: 756480, ~: 637982)
SSTORE2Test:testReadInvalidPointerRevert(address) (runs: 256, μ: 725554, ~: 637725)
SSTORE2Test:testReadInvalidPointerReverts() (gas: 3215)
SSTORE2Test:testWriteRead() (gas: 76106)
SSTORE2Test:testWriteRead(bytes) (runs: 256, μ: 817873, ~: 686007)
SSTORE2Test:testWriteReadCustomBounds() (gas: 34609)
SSTORE2Test:testWriteReadCustomBounds(bytes,uint256,uint256) (runs: 256, μ: 707651, ~: 672156)
SSTORE2Test:testWriteReadCustomBoundsOutOfRangeReverts(bytes,uint256,uint256) (runs: 256, μ: 801287, ~: 680107)
SSTORE2Test:testWriteReadCustomStartBound() (gas: 34843)
SSTORE2Test:testWriteReadCustomStartBound(bytes,uint256) (runs: 256, μ: 775018, ~: 682216)
SSTORE2Test:testWriteReadCustomStartBoundOutOfRangeReverts(bytes,uint256) (runs: 256, μ: 771432, ~: 679970)
SSTORE2Test:testWriteReadDeterministic(bytes) (runs: 256, μ: 846559, ~: 760384)
SSTORE2Test:testWriteReadEmptyBound() (gas: 33835)
SSTORE2Test:testWriteReadEmptyOutOfBoundsReverts() (gas: 36473)
SSTORE2Test:testWriteReadFullBoundedRead() (gas: 76146)
SSTORE2Test:testWriteReadFullStartBound() (gas: 35075)
SSTORE2Test:testWriteReadOutOfBoundsReverts() (gas: 36473)
SSTORE2Test:testWriteReadOutOfStartBoundReverts() (gas: 36477)
SSTORE2Test:test__codesize() (gas: 8820)
SSTORE2Test:testWriteRead() (gas: 76122)
SSTORE2Test:testWriteRead(bytes) (runs: 256, μ: 851639, ~: 682205)
SSTORE2Test:testWriteReadCustomBounds() (gas: 34603)
SSTORE2Test:testWriteReadCustomBounds(bytes,uint256,uint256) (runs: 256, μ: 774680, ~: 671639)
SSTORE2Test:testWriteReadCustomBoundsOutOfRangeReverts(bytes,uint256,uint256) (runs: 256, μ: 806244, ~: 675279)
SSTORE2Test:testWriteReadCustomStartBound() (gas: 34859)
SSTORE2Test:testWriteReadCustomStartBound(bytes,uint256) (runs: 256, μ: 796478, ~: 679077)
SSTORE2Test:testWriteReadCustomStartBoundOutOfRangeReverts(bytes,uint256) (runs: 256, μ: 783267, ~: 675496)
SSTORE2Test:testWriteReadDeterministic(bytes) (runs: 256, μ: 851345, ~: 755469)
SSTORE2Test:testWriteReadEmptyBound() (gas: 33829)
SSTORE2Test:testWriteReadEmptyOutOfBoundsReverts() (gas: 36489)
SSTORE2Test:testWriteReadFullBoundedRead() (gas: 76162)
SSTORE2Test:testWriteReadFullStartBound() (gas: 35091)
SSTORE2Test:testWriteReadOutOfBoundsReverts() (gas: 36467)
SSTORE2Test:testWriteReadOutOfStartBoundReverts() (gas: 36471)
SSTORE2Test:testWriteWithTooBigDataReverts() (gas: 29701830)
SSTORE2Test:test__codesize() (gas: 9671)
SafeCastLibTest:testSafeCastToInt(int256) (runs: 256, μ: 4384, ~: 3415)
SafeCastLibTest:testSafeCastToInt256(uint256) (runs: 256, μ: 931, ~: 390)
SafeCastLibTest:testSafeCastToIntBench() (gas: 383456)
Expand Down
12 changes: 12 additions & 0 deletions src/utils/SSTORE2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ library SSTORE2 {
// Add 1 to data size since we are prefixing it with a STOP opcode.
let dataSize := add(originalDataLength, DATA_OFFSET)

// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataSize, 0xffff))

/**
* ------------------------------------------------------------------------------+
* Opcode | Mnemonic | Stack | Memory |
Expand Down Expand Up @@ -93,6 +97,10 @@ library SSTORE2 {
let originalDataLength := mload(data)
let dataSize := add(originalDataLength, DATA_OFFSET)

// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataSize, 0xffff))

mstore(data, or(0x61000080600a3d393df300, shl(0x40, dataSize)))

// Deploy a new contract with the generated creation code.
Expand All @@ -119,6 +127,10 @@ library SSTORE2 {
let originalDataLength := mload(data)
let dataSize := add(originalDataLength, DATA_OFFSET)

// Do a out-of-gas revert if `dataSize` is more than 2 bytes.
// The actual EVM limit may be smaller and may change over time.
returndatacopy(returndatasize(), returndatasize(), gt(dataSize, 0xffff))

mstore(data, or(0x61000080600a3d393df300, shl(0x40, dataSize)))

hash := keccak256(add(data, 0x15), add(dataSize, 0xa))
Expand Down
28 changes: 28 additions & 0 deletions test/SSTORE2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,32 @@ contract SSTORE2Test is SoladyTest {
address pointer = SSTORE2.write(testBytes);
assertEq(pointer.code, deterministicPointer.code);
}

function testWriteWithTooBigDataReverts() public {
bytes memory data = _dummyData(0xfffe);
address pointer = this.write(data);
assertEq(SSTORE2.read(pointer), data);
vm.expectRevert();
pointer = this.write(_dummyData(0xffff));
}

function write(bytes memory data) public returns (address) {
return SSTORE2.write(data);
}

function _dummyData(uint256 n) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(result, n)
mstore(0x00, n)
mstore(0x20, 1)
mstore(add(0x20, result), keccak256(0x00, 0x40))
mstore(0x20, 2)
mstore(add(add(0x20, result), n), keccak256(0x00, 0x40))
mstore(0x20, 3)
mstore(add(result, n), keccak256(0x00, 0x40))
mstore(0x40, add(add(0x20, result), n))
}
}
}

0 comments on commit 58a0d26

Please sign in to comment.