diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index fb2ab3156..bcd4f9d68 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -206,16 +206,9 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) { - // We do not check the calldata size, everything is zero-padded. - unsigned offset(CompilerUtils::dataStartOffset); + // We do not check the calldata size, everything is zero-paddedd - bigint parameterHeadEnd = offset; - for (TypePointer const& type: _typeParameters) - parameterHeadEnd += type->isDynamicallySized() ? 32 : type->getCalldataEncodedSize(); - solAssert(parameterHeadEnd <= numeric_limits::max(), "Arguments too large."); - - unsigned stackHeightOfPreviousDynamicArgument = 0; - ArrayType const* previousDynamicType = nullptr; + m_context << u256(CompilerUtils::dataStartOffset); for (TypePointer const& type: _typeParameters) { switch (type->getCategory()) @@ -223,34 +216,31 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool case Type::Category::Array: if (type->isDynamicallySized()) { - // put on stack: data_offset length - unsigned newStackHeight = m_context.getStackHeight(); - if (previousDynamicType) - { - // Retrieve data start offset by adding length to start offset of previous dynamic type - unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument; - solAssert(stackDepth <= 16, "Stack too deep."); - m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth); - ArrayUtils(m_context).convertLengthToSize(*previousDynamicType, true); - m_context << eth::Instruction::ADD; - } - else - m_context << u256(parameterHeadEnd); - stackHeightOfPreviousDynamicArgument = newStackHeight; - previousDynamicType = &dynamic_cast(*type); - offset += CompilerUtils(m_context).loadFromMemory(offset, IntegerType(256), !_fromMemory); + // put on stack: data_pointer length + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); + // stack: data_offset next_pointer + //@todo once we support nested arrays, this offset needs to be dynamic. + m_context << eth::Instruction::SWAP1 << u256(CompilerUtils::dataStartOffset); + m_context << eth::Instruction::ADD; + // stack: next_pointer data_pointer + // retrieve length + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); + // stack: next_pointer length data_pointer + m_context << eth::Instruction::SWAP2; } else { - m_context << u256(offset); - offset += type->getCalldataEncodedSize(); + // leave the pointer on the stack + m_context << eth::Instruction::DUP1; + m_context << u256(type->getCalldataEncodedSize()) << eth::Instruction::ADD; } break; default: solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); - offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true); + CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true); } } + m_context << eth::Instruction::POP; } void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) diff --git a/test/libsolidity/SolidityCompiler.cpp b/test/libsolidity/SolidityCompiler.cpp index 7b0ceedb6..aa83c4650 100644 --- a/test/libsolidity/SolidityCompiler.cpp +++ b/test/libsolidity/SolidityCompiler.cpp @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 70; + unsigned boilerplateSize = 73; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x2, @@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(ifStatement) " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 57; - unsigned boilerplateSize = 70; + unsigned shift = 60; + unsigned boilerplateSize = 73; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), @@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops) " function f() { while(true){1;break;2;continue;3;return;4;} }" "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 57; - unsigned boilerplateSize = 70; + unsigned shift = 60; + unsigned boilerplateSize = 73; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x1, diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f32439a27..ed5f1acdf 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2962,12 +2962,13 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) } )"; compileAndRun(sourceCode); + string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); - bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13); string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); bytes calldata = encodeArgs( - 12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13, - innercalldata1, innercalldata2); + 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, + u256(innercalldata1.length()), innercalldata1, + u256(innercalldata2.length()), innercalldata2); BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata) == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); } @@ -3383,9 +3384,10 @@ BOOST_AUTO_TEST_CASE(external_array_args) compileAndRun(sourceCode); bytes params = encodeArgs( 1, 2, 3, 4, 5, 6, 7, 8, // a - 3, // b.length + 32 * (8 + 1 + 5 + 1 + 1 + 1), // offset to b 21, 22, 23, 24, 25, // c 0, 1, 2, // (a,b,c)_index + 3, // b.length 11, 12, 13 // b ); BOOST_CHECK(callContractFunction("test(uint256[8],uint256[],uint256[5],uint256,uint256,uint256)", params) == encodeArgs(1, 12, 23)); @@ -3422,8 +3424,8 @@ BOOST_AUTO_TEST_CASE(bytes_index_access) 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; - BOOST_CHECK(callContractFunction("direct(bytes,uint256)", u256(array.length()), 32, array) == encodeArgs(32)); - BOOST_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", u256(array.length()), 32, array) == encodeArgs(32)); + BOOST_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array) == encodeArgs(33)); + BOOST_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array) == encodeArgs(33)); BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193)); } @@ -3474,6 +3476,7 @@ BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs( 21, 22, 23, 24, 25, 26, 27, 28, 29, // a + u256(32 * (9 + 1)), 4, // size of b 1, 2, 3, // b[0] 11, 12, 13, // b[1] @@ -3502,7 +3505,7 @@ BOOST_AUTO_TEST_CASE(array_copy_nested_array) )"; compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("test(uint256[2][])", encodeArgs( - 3, + 32, 3, 7, 8, 9, 10, 11, 12