Browse Source

Fix for arrays containing mappings.

cl-refactor
chriseth 10 years ago
parent
commit
8103fcbf98
  1. 19
      libsolidity/ArrayUtils.cpp
  2. 1
      libsolidity/LValue.cpp
  3. 37
      test/SolidityEndToEndTest.cpp

19
libsolidity/ArrayUtils.cpp

@ -65,6 +65,16 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
if (_targetType.isDynamicallySized())
// store new target length
m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
if (sourceBaseType->getCategory() == Type::Category::Mapping)
{
solAssert(targetBaseType->getCategory() == Type::Category::Mapping, "");
solAssert(_sourceType.getLocation() == ArrayType::Location::Storage, "");
// nothing to copy
m_context
<< eth::Instruction::POP << eth::Instruction::POP
<< eth::Instruction::POP << eth::Instruction::POP;
return;
}
// compute hashes (data positions)
m_context << eth::Instruction::SWAP1;
if (_targetType.isDynamicallySized())
@ -114,7 +124,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
else if (sourceBaseType->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, true, true, false);
else
solAssert(false, "Copying of unknown type requested.");
solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString());
m_context << eth::dupInstruction(2 + sourceBaseType->getSizeOnStack());
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
}
@ -148,7 +158,7 @@ void ArrayUtils::clearArray(ArrayType const& _type) const
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
if (_type.isDynamicallySized())
clearDynamicArray(_type);
else if (_type.getLength() == 0)
else if (_type.getLength() == 0 || _type.getBaseType()->getCategory() == Type::Category::Mapping)
m_context << eth::Instruction::POP;
else if (_type.getLength() < 5) // unroll loop for small arrays @todo choose a good value
{
@ -242,6 +252,11 @@ void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const
void ArrayUtils::clearStorageLoop(Type const& _type) const
{
if (_type.getCategory() == Type::Category::Mapping)
{
m_context << eth::Instruction::POP;
return;
}
// stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart;

1
libsolidity/LValue.cpp

@ -212,6 +212,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
}
else
{
solAssert(m_dataType.isValueType(), "Clearing of unsupported type requested: " + m_dataType.toString());
if (m_size == 0 && _removeReference)
m_context << eth::Instruction::POP;
else if (m_size == 1)

37
test/SolidityEndToEndTest.cpp

@ -3070,6 +3070,43 @@ BOOST_AUTO_TEST_CASE(array_copy_nested_array)
)) == encodeArgs(10));
}
BOOST_AUTO_TEST_CASE(array_copy_including_mapping)
{
char const* sourceCode = R"(
contract c {
mapping(uint=>uint)[90][] large;
mapping(uint=>uint)[3][] small;
function test() returns (uint r) {
large.length = small.length = 7;
large[3][2][0] = 2;
large[1] = large[3];
small[3][2][0] = 2;
small[1] = small[2];
r = ((
small[3][2][0] * 0x100 |
small[1][2][0]) * 0x100 |
large[3][2][0]) * 0x100 |
large[1][2][0];
delete small;
delete large;
}
function clear() returns (uint r) {
large.length = small.length = 7;
small[3][2][0] = 0;
large[3][2][0] = 0;
small.length = large.length = 0;
return 7;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(0x02000200));
// storage is not empty because we cannot delete the mappings
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == encodeArgs(7));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
{
char const* sourceCode = R"(

Loading…
Cancel
Save