mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fixes assembly bug and adds tests to cover it.
This commit is contained in:
parent
98d52beba3
commit
fea0d116f7
@ -848,9 +848,9 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
|||||||
}
|
}
|
||||||
case 1 {
|
case 1 {
|
||||||
// long byte array
|
// long byte array
|
||||||
|
mstore(0, ref)
|
||||||
let length := div(slot_value, 2)
|
let length := div(slot_value, 2)
|
||||||
let slot := keccak256(0, 0x20)
|
let slot := keccak256(0, 0x20)
|
||||||
mstore(0, ref)
|
|
||||||
switch length
|
switch length
|
||||||
case 32
|
case 32
|
||||||
{
|
{
|
||||||
@ -861,14 +861,13 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
|
|||||||
}
|
}
|
||||||
default
|
default
|
||||||
{
|
{
|
||||||
let slot_offset := div(sub(length, 1), 32)
|
let offset_inside_slot := and(sub(length, 1), 0x1f)
|
||||||
let length_offset := and(sub(length, 1), 0x1f)
|
slot := add(slot, div(sub(length, 1), 32))
|
||||||
slot := add(slot, slot_offset)
|
|
||||||
let data := sload(slot)
|
let data := sload(slot)
|
||||||
|
|
||||||
// Zero-out the suffix of the byte array by masking it.
|
// Zero-out the suffix of the byte array by masking it.
|
||||||
// ((1<<(8 * (32 - offset))) - 1)
|
// ((1<<(8 * (32 - offset))) - 1)
|
||||||
let mask := sub(exp(0x100, sub(32, length_offset)), 1)
|
let mask := sub(exp(0x100, sub(32, offset_inside_slot)), 1)
|
||||||
data := and(not(mask), data)
|
data := and(not(mask), data)
|
||||||
sstore(slot, data)
|
sstore(slot, data)
|
||||||
|
|
||||||
|
@ -5161,6 +5161,9 @@ BOOST_AUTO_TEST_CASE(array_pop_uint24_transition)
|
|||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
contract c {
|
contract c {
|
||||||
|
uint256 a;
|
||||||
|
uint256 b;
|
||||||
|
uint256 c;
|
||||||
uint24[] data;
|
uint24[] data;
|
||||||
function test() public returns (uint24 x, uint24 y) {
|
function test() public returns (uint24 x, uint24 y) {
|
||||||
for (uint i = 1; i <= 30; i++)
|
for (uint i = 1; i <= 30; i++)
|
||||||
@ -5185,6 +5188,9 @@ BOOST_AUTO_TEST_CASE(array_pop_array_transition)
|
|||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
contract c {
|
contract c {
|
||||||
|
uint256 a;
|
||||||
|
uint256 b;
|
||||||
|
uint256 c;
|
||||||
uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
uint16[] inner = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||||
uint16[][] data;
|
uint16[][] data;
|
||||||
function test() public returns (uint x, uint y, uint z) {
|
function test() public returns (uint x, uint y, uint z) {
|
||||||
@ -5260,27 +5266,13 @@ BOOST_AUTO_TEST_CASE(byte_array_pop)
|
|||||||
ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 1, 1));
|
ABI_CHECK(callContractFunction("test()"), encodeArgs(2, 1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(byte_array_pop_long)
|
|
||||||
{
|
|
||||||
char const* sourceCode = R"(
|
|
||||||
contract c {
|
|
||||||
bytes data;
|
|
||||||
function test() public returns (uint l) {
|
|
||||||
for (uint i = 0; i < 33; i++)
|
|
||||||
data.push(byte(i));
|
|
||||||
data.pop();
|
|
||||||
l = data.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
compileAndRun(sourceCode);
|
|
||||||
ABI_CHECK(callContractFunction("test()"), encodeArgs(32));
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(byte_array_pop_empty_exception)
|
BOOST_AUTO_TEST_CASE(byte_array_pop_empty_exception)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
contract c {
|
contract c {
|
||||||
|
uint256 a;
|
||||||
|
uint256 b;
|
||||||
|
uint256 c;
|
||||||
bytes data;
|
bytes data;
|
||||||
function test() public returns (bool) {
|
function test() public returns (bool) {
|
||||||
data.pop();
|
data.pop();
|
||||||
@ -5312,22 +5304,52 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty)
|
|||||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty_long)
|
BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
contract c {
|
contract c {
|
||||||
|
uint256 a;
|
||||||
|
uint256 b;
|
||||||
|
uint256 c;
|
||||||
bytes data;
|
bytes data;
|
||||||
function test() public returns (uint l) {
|
function test() public returns (bool) {
|
||||||
for (uint i = 0; i < 33; i++)
|
for (uint8 i = 0; i <= 40; i++)
|
||||||
data.push(3);
|
data.push(byte(i+1));
|
||||||
for (uint j = 0; j < 33; j++)
|
for (int8 j = 40; j >= 0; j--) {
|
||||||
|
require(data[uint8(j)] == byte(j+1));
|
||||||
|
require(data.length == uint8(j+1));
|
||||||
data.pop();
|
data.pop();
|
||||||
l = data.length;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(callContractFunction("test()"), encodeArgs(0));
|
ABI_CHECK(callContractFunction("test()"), encodeArgs(true));
|
||||||
|
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract c {
|
||||||
|
uint256 a;
|
||||||
|
uint256 b;
|
||||||
|
bytes data;
|
||||||
|
function test() public {
|
||||||
|
for (uint8 i = 0; i <= 40; i++)
|
||||||
|
data.push(3);
|
||||||
|
for (uint8 j = 0; j <= 40; j++) {
|
||||||
|
assembly {
|
||||||
|
mstore(0, "garbage")
|
||||||
|
}
|
||||||
|
data.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode);
|
||||||
|
ABI_CHECK(callContractFunction("test()"), encodeArgs());
|
||||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user