Properly cleanup after copying dynamic-array to storage for packed types

This commit is contained in:
Harikrishnan Mulackal 2020-10-01 19:07:56 +02:00 committed by hrkrshnn
parent 87e1934bee
commit 1bdbc10110
5 changed files with 81 additions and 3 deletions

View File

@ -1,5 +1,8 @@
### 0.7.3 (unreleased) ### 0.7.3 (unreleased)
Important Bugfixes:
* Code Generator: Properly cleanup after copying dynamic-array to storage for packed types.
Compiler Features: Compiler Features:
* SMTChecker: Support ``addmod`` and ``mulmod``. * SMTChecker: Support ``addmod`` and ``mulmod``.
* SMTChecker: Support array slices. * SMTChecker: Support array slices.

View File

@ -290,7 +290,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// stack: target_ref target_data_end source_data_pos target_data_pos_updated source_data_end // stack: target_ref target_data_end source_data_pos target_data_pos_updated source_data_end
_context << Instruction::POP << Instruction::SWAP1 << Instruction::POP; _context << Instruction::POP << Instruction::SWAP1 << Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated // stack: target_ref target_data_end target_data_pos_updated
utils.clearStorageLoop(targetBaseType); if (targetBaseType->storageBytes() < 32)
utils.clearStorageLoop(TypeProvider::uint256());
else
utils.clearStorageLoop(targetBaseType);
_context << Instruction::POP; _context << Instruction::POP;
} }
); );
@ -922,6 +925,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
void ArrayUtils::clearStorageLoop(TypePointer _type) const void ArrayUtils::clearStorageLoop(TypePointer _type) const
{ {
solAssert(_type->storageBytes() >= 32, "");
m_context.callLowLevelFunction( m_context.callLowLevelFunction(
"$clearStorageLoop_" + _type->identifier(), "$clearStorageLoop_" + _type->identifier(),
2, 2,

View File

@ -633,8 +633,8 @@ BOOST_AUTO_TEST_CASE(optimise_multi_stores)
)"; )";
compileBothVersions(sourceCode); compileBothVersions(sourceCode);
compareVersions("f()"); compareVersions("f()");
BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, Instruction::SSTORE), 9); BOOST_CHECK_EQUAL(numInstructions(m_nonOptimizedBytecode, Instruction::SSTORE), 8);
BOOST_CHECK_EQUAL(numInstructions(m_optimizedBytecode, Instruction::SSTORE), 8); BOOST_CHECK_EQUAL(numInstructions(m_optimizedBytecode, Instruction::SSTORE), 7);
} }
BOOST_AUTO_TEST_CASE(optimise_constant_to_codecopy) BOOST_AUTO_TEST_CASE(optimise_constant_to_codecopy)

View File

@ -0,0 +1,23 @@
// Test to see if cleanup is performed properly during array copying
contract C {
uint128[] x;
function f() public returns(bool) {
x.push(42); x.push(42); x.push(42); x.push(42);
uint128[] memory y = new uint128[](1);
y[0] = 23;
x = y;
assembly { sstore(x.slot, 4) }
assert(x[0] == 23);
assert(x[1] == 0);
assert(x[2] == 0);
// Issue 9832: the cleanup was only performed for the first packed type leaving the rest of
// the slot dirty.
assert(x[3] == 0);
return true;
}
}
// ----
// f() -> true

View File

@ -0,0 +1,48 @@
// Issue 9832: Test to see if cleanup is performed properly after array copying
contract C {
uint40[] x;
function f() public returns(bool) {
x.push(42); x.push(42); x.push(42); x.push(42);
x.push(42); x.push(42); x.push(42); x.push(42);
x.push(42); x.push(42); x.push(42); x.push(42);
x.push(42); x.push(42); x.push(42); x.push(42);
x.push(42); x.push(42); x.push(42); x.push(42);
uint40[] memory y = new uint40[](1);
y[0] = 23;
x = y;
assembly { sstore(x.slot, 20) }
assert(x[0] == 23);
assert(x[1] == 0);
assert(x[2] == 0);
assert(x[3] == 0);
assert(x[4] == 0);
assert(x[5] == 0);
assert(x[6] == 0);
assert(x[7] == 0);
assert(x[8] == 0);
assert(x[9] == 0);
assert(x[10] == 0);
assert(x[11] == 0);
assert(x[12] == 0);
assert(x[13] == 0);
assert(x[14] == 0);
assert(x[15] == 0);
assert(x[16] == 0);
assert(x[17] == 0);
assert(x[18] == 0);
assert(x[19] == 0);
return true;
}
}
// ----
// f() -> true