From 14d7ca49c09bf9d0be0ff932fbfc42e9ca3dc9e6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 20 Oct 2020 15:49:54 +0200 Subject: [PATCH 1/4] Rename function. --- libsolidity/codegen/YulUtilFunctions.cpp | 4 ++-- libsolidity/codegen/YulUtilFunctions.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 051b4bf99..5a7d32b01 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1462,7 +1462,7 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) }); } -string YulUtilFunctions::copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType) +string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType) { solAssert( *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), @@ -2154,7 +2154,7 @@ string YulUtilFunctions::updateStorageValueFunction( )"); templ("functionName", functionName); templ("value", suffixedVariableNameList("value_", 0, _fromType.sizeOnStack())); - templ("copyArrayToStorage", copyArrayToStorage( + templ("copyArrayToStorage", copyArrayToStorageFunction( dynamic_cast(_fromType), dynamic_cast(_toType) )); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index b84dad4f9..15b678393 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -188,7 +188,7 @@ public: /// @returns the name of a function that will copy array from calldata or memory to storage /// signature (to_slot, from_ptr) -> - std::string copyArrayToStorage(ArrayType const& _fromType, ArrayType const& _toType); + std::string copyArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType); /// Returns the name of a function that will convert a given length to the /// size in memory (number of storage slots or calldata/memory bytes) it From 1066af3b98417a62095d86e360913e8874b1cde6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 20 Oct 2020 17:05:58 +0200 Subject: [PATCH 2/4] Copy byte array to storage. --- libsolidity/codegen/YulUtilFunctions.cpp | 81 ++++++++++++++++++- libsolidity/codegen/YulUtilFunctions.h | 4 + .../abiEncoderV1/abi_decode_v2_storage.sol | 2 + .../abi_decode_simple_storage.sol | 2 + .../array/bytes_delete_element.sol | 2 + .../array/bytes_length_member.sol | 2 + .../array/copying/bytes_memory_to_storage.sol | 2 + .../copying/calldata_bytes_to_storage.sol | 2 + .../various/destructuring_assignment.sol | 2 + .../semanticTests/various/store_bytes.sol | 2 + 10 files changed, 100 insertions(+), 1 deletion(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 5a7d32b01..e3114944b 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1468,7 +1468,8 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType, *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), "" ); - solUnimplementedAssert(!_fromType.isByteArray(), ""); + if (_fromType.isByteArray()) + return copyByteArrayToStorageFunction(_fromType, _toType); solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), ""); string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); @@ -1561,6 +1562,84 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType, }); } + +string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType) +{ + solAssert( + *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), + "" + ); + solAssert(_fromType.isByteArray(), ""); + solAssert(_toType.isByteArray(), ""); + solUnimplementedAssert(!_fromType.dataStoredIn(DataLocation::Storage), ""); + + string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); + return m_functionCollector.createFunction(functionName, [&](){ + Whiskers templ(R"( + function (slot, src, len) { + let newLen := (src, len) + // Make sure array length is sane + if gt(newLen, 0xffffffffffffffff) { () } + + let oldLen := (sload(slot)) + + + src := add(src, 0x20) + + + // This is not needed in all branches. + let dstDataArea + if or(gt(oldLen, 31), gt(newLen, 31)) { + dstDataArea := (slot) + } + + if gt(oldLen, 31) { + // potentially truncate data + let deleteStart := add(dstDataArea, div(add(newLen, 31), 32)) + if lt(newLen, 32) { deleteStart := dstDataArea } + (deleteStart, add(dstDataArea, div(add(oldLen, 31), 32))) + } + switch gt(newLen, 31) + case 1 { + let loopEnd := and(newLen, not(0x1f)) + let dstPtr := dstDataArea + let i := 0 + for { } lt(i, loopEnd) { i := add(i, 32) } { + sstore(dstPtr, (add(src, i))) + dstPtr := add(dstPtr, 1) + } + if lt(loopEnd, newLen) { + let lastValue := (add(src, i)) + sstore(dstPtr, (lastValue, and(newLen, 0x1f))) + } + sstore(slot, add(mul(newLen, 2), 1)) + } + default { + let value := 0 + if newLen { + value := (src) + } + sstore(slot, (value, newLen)) + } + } + )"); + templ("functionName", functionName); + bool fromCalldata = _fromType.dataStoredIn(DataLocation::CallData); + templ("fromMemory", _fromType.dataStoredIn(DataLocation::Memory)); + templ("fromCalldata", fromCalldata); + templ("arrayLength", arrayLengthFunction(_fromType)); + templ("panic", panicFunction()); + templ("byteArrayLength", extractByteArrayLengthFunction()); + templ("dstDataLocation", arrayDataAreaFunction(_toType)); + templ("clearStorageRange", clearStorageRangeFunction(*_toType.baseType())); + templ("readFromCalldataOrMemory", readFromMemoryOrCalldata(*TypeProvider::uint256(), fromCalldata)); + templ("maskBytes", maskBytesFunctionDynamic()); + templ("byteArrayCombineShort", shortByteArrayEncodeUsedAreaSetLengthFunction()); + + return templ.render(); + }); +} + string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type) { string functionName = "array_convert_length_to_size_" + _type.identifier(); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 15b678393..28467dceb 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -190,6 +190,10 @@ public: /// signature (to_slot, from_ptr) -> std::string copyArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType); + /// @returns the name of a function that will copy a byte array from calldata or memory to storage + /// signature (to_slot, from_ptr) -> + std::string copyByteArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType); + /// Returns the name of a function that will convert a given length to the /// size in memory (number of storage slots or calldata/memory bytes) it /// will require. diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol index 95b667e47..79c450556 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol @@ -20,5 +20,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb diff --git a/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol index d08e2ff82..119c33aeb 100644 --- a/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol +++ b/test/libsolidity/semanticTests/abiencodedecode/abi_decode_simple_storage.sol @@ -7,5 +7,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(bytes): 0x20, 0x80, 0x21, 0x40, 0x7, "abcdefg" -> 0x21, 0x40, 0x7, "abcdefg" diff --git a/test/libsolidity/semanticTests/array/bytes_delete_element.sol b/test/libsolidity/semanticTests/array/bytes_delete_element.sol index 2f6b8176d..6cf0da3bb 100644 --- a/test/libsolidity/semanticTests/array/bytes_delete_element.sol +++ b/test/libsolidity/semanticTests/array/bytes_delete_element.sol @@ -14,5 +14,7 @@ contract c { uint8(data[97]) == 97; } } +// ==== +// compileViaYul: also // ---- // test1() -> true diff --git a/test/libsolidity/semanticTests/array/bytes_length_member.sol b/test/libsolidity/semanticTests/array/bytes_length_member.sol index d35fc88d3..fbff51f02 100644 --- a/test/libsolidity/semanticTests/array/bytes_length_member.sol +++ b/test/libsolidity/semanticTests/array/bytes_length_member.sol @@ -10,6 +10,8 @@ contract c { bytes data; } +// ==== +// compileViaYul: also // ---- // getLength() -> 0 // set(): 1, 2 -> true diff --git a/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol index eebdb7e9b..75bd9c5b3 100644 --- a/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/bytes_memory_to_storage.sol @@ -6,5 +6,7 @@ contract C { return s[0]; } } +// ==== +// compileViaYul: also // ---- // f() -> "a" diff --git a/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol b/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol index 07041910d..efd67e10c 100644 --- a/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/calldata_bytes_to_storage.sol @@ -5,5 +5,7 @@ contract C { return s[0]; } } +// ==== +// compileViaYul: also // ---- // f(bytes): 0x20, 0x08, "abcdefgh" -> "a" diff --git a/test/libsolidity/semanticTests/various/destructuring_assignment.sol b/test/libsolidity/semanticTests/various/destructuring_assignment.sol index 0c8dc3835..345d76ca1 100644 --- a/test/libsolidity/semanticTests/various/destructuring_assignment.sol +++ b/test/libsolidity/semanticTests/various/destructuring_assignment.sol @@ -32,5 +32,7 @@ contract C { } } +// ==== +// compileViaYul: also // ---- // f(bytes): 0x20, 0x5, "abcde" -> 0 diff --git a/test/libsolidity/semanticTests/various/store_bytes.sol b/test/libsolidity/semanticTests/various/store_bytes.sol index 4b92a251a..34c0b6f3d 100644 --- a/test/libsolidity/semanticTests/various/store_bytes.sol +++ b/test/libsolidity/semanticTests/various/store_bytes.sol @@ -8,6 +8,8 @@ contract C { bytes savedData; } +// ==== +// compileViaYul: also // ---- // save() -> 24 # empty copy loop # // save(): "abcdefg" -> 24 From 6ec5612f35396ef1da9252d9aa164988704d3c98 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 28 Oct 2020 17:45:11 +0100 Subject: [PATCH 3/4] Enable more tests. --- test/libsolidity/SolidityEndToEndTest.cpp | 159 +++++++++++------- .../storage/empty_nonempty_empty.sol | 2 + 2 files changed, 100 insertions(+), 61 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f410e15a5..d0490f4af 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2857,11 +2857,14 @@ BOOST_AUTO_TEST_CASE(delete_removes_bytes_data) bytes data; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("---", 7), bytes()); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("---", 7), bytes()); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("del()", 7), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) @@ -2873,13 +2876,16 @@ BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) bytes data; } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - sendMessage(bytes(), false); - BOOST_CHECK(m_transactionSuccessful); - BOOST_CHECK(m_output.empty()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + sendMessage(bytes(), false); + BOOST_CHECK(m_transactionSuccessful); + BOOST_CHECK(m_output.empty()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(copy_removes_bytes_data) @@ -3125,17 +3131,21 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) } } )"; - compileAndRun(sourceCode); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() - string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); - string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); - bytes calldata = encodeArgs( - 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, - u256(innercalldata1.length()), innercalldata1, - u256(innercalldata2.length()), innercalldata2); - ABI_CHECK( - callContractFunction("test(uint256,bytes,bytes,uint256)", calldata), - encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())) + compileAndRun(sourceCode); + + string innercalldata1 = asString(FixedHash<4>(util::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); + string innercalldata2 = asString(FixedHash<4>(util::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); + bytes calldata = encodeArgs( + 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, + u256(innercalldata1.length()), innercalldata1, + u256(innercalldata2.length()), innercalldata2); + ABI_CHECK( + callContractFunction("test(uint256,bytes,bytes,uint256)", calldata), + encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())) + ); ); } @@ -3239,12 +3249,16 @@ BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup) function clear() public { delete data; } } )"; - compileAndRun(sourceCode); - BOOST_CHECK(storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("fill()"), encodeArgs(8)); - BOOST_CHECK(!storageEmpty(m_contractAddress)); - ABI_CHECK(callContractFunction("clear()"), bytes()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + + compileAndRun(sourceCode); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("fill()"), encodeArgs(8)); + BOOST_CHECK(!storageEmpty(m_contractAddress)); + ABI_CHECK(callContractFunction("clear()"), bytes()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) @@ -3361,20 +3375,24 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_abi) } } )"; - compileAndRun(sourceCode); - bytes valueSequence; - for (size_t i = 0; i < 101; ++i) - valueSequence += toBigEndian(u256(i)); - ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence); - ABI_CHECK(callContractFunction("test4()"), - encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + - encodeArgs(101) + valueSequence + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + + compileAndRun(sourceCode); + bytes valueSequence; + for (size_t i = 0; i < 101; ++i) + valueSequence += toBigEndian(u256(i)); + ABI_CHECK(callContractFunction("test1()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test2()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test3()"), encodeArgs(0x20, 101) + valueSequence); + ABI_CHECK(callContractFunction("test4()"), + encodeArgs(0x20, 5, 0xa0, 0xa0 + 102 * 32 * 1, 0xa0 + 102 * 32 * 2, 0xa0 + 102 * 32 * 3, 0xa0 + 102 * 32 * 4) + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + + encodeArgs(101) + valueSequence + ); ); } @@ -3400,9 +3418,12 @@ BOOST_AUTO_TEST_CASE(array_pop_uint16_transition) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(38, 28, 18)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(array_pop_uint24_transition) @@ -3427,9 +3448,12 @@ BOOST_AUTO_TEST_CASE(array_pop_uint24_transition) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(20, 10)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(array_pop_array_transition) @@ -3475,9 +3499,12 @@ BOOST_AUTO_TEST_CASE(array_pop_storage_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) @@ -3495,9 +3522,12 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_storage_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs()); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs()); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty) @@ -3520,9 +3550,12 @@ BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty) } } )"; - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); - BOOST_CHECK(storageEmpty(m_contractAddress)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("test()"), encodeArgs(true)); + BOOST_CHECK(storageEmpty(m_contractAddress)); + ); } BOOST_AUTO_TEST_CASE(byte_array_pop_long_storage_empty_garbage_ref) @@ -3598,15 +3631,19 @@ BOOST_AUTO_TEST_CASE(bytes_index_access) } } )"; - compileAndRun(sourceCode); string array{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; - ABI_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); - ABI_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); - ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); + ALSO_VIA_YUL( + DISABLE_EWASM_TESTRUN() + + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("direct(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); + ABI_CHECK(callContractFunction("storageCopyRead(bytes,uint256)", 64, 33, u256(array.length()), array), encodeArgs(33)); + ABI_CHECK(callContractFunction("storageWrite()"), encodeArgs(0x193)); + ); } BOOST_AUTO_TEST_CASE(array_copy_calldata_storage) diff --git a/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol b/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol index 70d72ac62..234f0191f 100644 --- a/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol +++ b/test/libsolidity/semanticTests/storage/empty_nonempty_empty.sol @@ -2,6 +2,8 @@ contract Test { bytes x; function set(bytes memory _a) public { x = _a; } } +// ==== +// compileViaYul: also // ---- // set(bytes): 0x20, 3, "abc" // storage: nonempty From ef503f180cd1539b1843a4e9e07b6846f897abc6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 29 Oct 2020 17:03:04 +0100 Subject: [PATCH 4/4] New test. --- .../copy_byte_array_in_struct_to_storage.sol | 42 ++++++++++++++++ .../copying/copy_byte_array_to_storage.sol | 50 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol create mode 100644 test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol diff --git a/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol new file mode 100644 index 000000000..2f983e022 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/copy_byte_array_in_struct_to_storage.sol @@ -0,0 +1,42 @@ +pragma experimental ABIEncoderV2; +struct S { + uint16 x; + bytes a; + uint16 y; + bytes b; +} +contract C { + uint padding; + S data; + + function f() public returns (bytes memory, bytes memory) { + S memory x; + x.x = 7; + x.b = "1234567890123456789012345678901 1234567890123456789012345678901 123456789"; + x.a = "abcdef"; + x.y = 9; + data = x; + return (data.a, data.b); + } + function g() public returns (bytes memory, bytes memory) { + S memory x; + x.x = 7; + x.b = "12345678923456789"; + x.a = "1234567890123456789012345678901 1234567890123456789012345678901 123456789"; + x.y = 9; + data = x; + return (data.a, data.b); + } + function h() public returns (bytes memory, bytes memory) { + S memory x; + data = x; + return (data.a, data.b); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x40, 0x80, 6, 0x6162636465660000000000000000000000000000000000000000000000000000, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000 +// g() -> 0x40, 0xc0, 0x49, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738393031323334353637383930313233343536373839303120, 0x3132333435363738390000000000000000000000000000000000000000000000, 0x11, 0x3132333435363738393233343536373839000000000000000000000000000000 +// h() -> 0x40, 0x60, 0x00, 0x00 +// storage: empty diff --git a/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol new file mode 100644 index 000000000..de36b0a29 --- /dev/null +++ b/test/libsolidity/semanticTests/array/copying/copy_byte_array_to_storage.sol @@ -0,0 +1,50 @@ +function dataslot() pure returns (bytes32) { + return keccak256(abi.encode(1)); +} + +function readDataSlot(uint offset) view returns (bytes32 r) { + bytes32 s = dataslot(); + assembly { r := sload(add(s, offset)) } +} + +function readDataSlot() view returns (bytes32) { + return readDataSlot(0); +} + +function readHead() view returns (bytes32 r) { + assembly { r := sload(1) } +} + +contract C { + uint padding; + bytes data; + + function f() public returns (uint) { + bytes32 zero; + if (!(readDataSlot() == zero)) return 1; + data = "abc"; + if (!(readDataSlot() == zero)) return 2; + data = "1234567890123456789012345678901234567890123456789012345678901234567890"; + if (!(readDataSlot() != zero)) return 3; + if (!(readDataSlot(1) != zero)) return 4; + if (!(readDataSlot(2) != zero)) return 5; + if (!(readDataSlot(3) == zero)) return 6; + if (!(readDataSlot(4) == zero)) return 7; + data = "abc"; + if (!(readDataSlot() == zero)) return 8; + if (!(readDataSlot(1) == zero)) return 9; + if (!(readDataSlot(2) == zero)) return 10; + if (!(readDataSlot(3) == zero)) return 11; + data = "1234567890123456789012345678901234567890123456789012345678901234567890"; + data = "123456789012345678901234567890123456"; + if (!(readDataSlot() != zero)) return 12; + if (!(readDataSlot(1) != zero)) return 13; + if (!(readDataSlot(2) == zero)) return 14; + if (!(readDataSlot(3) == zero)) return 15; + return 0xff; + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0xff