diff --git a/Changelog.md b/Changelog.md index 4467bd504234..67771723c4fc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Compiler Features: Bugfixes: * Code Generator: Fix ICE on parenthesized custom error construction in require statement. +* Code Generator: Fix ICE when assigning a calldata struct containing a member of external function type to a storage struct. * Commandline Interface: Report proper error instead of ICE on non-hex mixed-case address value given via `--libraries`. diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index af1c3ca3095a..7452302b03c7 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3792,6 +3792,11 @@ std::string YulUtilFunctions::copyStructToStorageFunction(StructType const& _fro { Type const& memberType = *structMembers[i].type; solAssert(memberType.memoryHeadSize() == 32, ""); + + // Value types cannot be dynamically encoded + if (_from.location() == DataLocation::CallData) + solAssert(!memberType.isDynamicallyEncoded() || !memberType.isValueType()); + auto const&[slotDiff, offset] = _to.storageOffsetsOfMember(structMembers[i].name); Whiskers t(R"( @@ -3799,16 +3804,15 @@ std::string YulUtilFunctions::copyStructToStorageFunction(StructType const& _fro let memberSrcPtr := add(value, ) - let := - - (value, memberSrcPtr) - - memberSrcPtr - - - - := () - + + let := (value, memberSrcPtr) + + + let := (memberSrcPtr) + + let := memberSrcPtr + + diff --git a/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol b/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol index 42001e191aa5..a86cc39ebb84 100644 --- a/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol +++ b/test/libsolidity/semanticTests/array/push/array_push_struct_from_calldata.sol @@ -17,6 +17,6 @@ contract c { // ---- // test((uint16,uint16,uint16[3],uint16[])): 0x20, 2, 3, 0, 0, 4, 0xC0, 4, 0, 0, 5, 0, 0 -> 2, 3, 4, 5 // gas irOptimized: 137153 -// gas legacy: 142414 +// gas legacy: 142398 // gas legacyOptimized: 137975 // gas ssaCFGOptimized: 136989 diff --git a/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member.sol b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member.sol new file mode 100644 index 000000000000..fb0cd9be7c03 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member.sol @@ -0,0 +1,18 @@ +pragma abicoder v2; +struct S { + function(uint) external fn_uint; +} + +contract C { + S storageStruct; + + function test(S calldata calldataStruct) public returns (bool) { + storageStruct = calldataStruct; + + assert(storageStruct.fn_uint.address == address(bytes20("01234567890123456789"))); + assert(storageStruct.fn_uint.selector == bytes4("abcd")); + return true; + } +} +// ---- +// test((function)): "01234567890123456789abcd" -> true diff --git a/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_array.sol b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_array.sol new file mode 100644 index 000000000000..f4ddc5dcde6b --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_array.sol @@ -0,0 +1,23 @@ +pragma abicoder v2; +struct S { + function(uint) external fn_uint; +} + +contract C { + S[] storageStruct; + + function test(S[] calldata calldataStruct) public returns (bool) { + storageStruct = calldataStruct; + + assert(storageStruct.length == 2); + assert(storageStruct[0].fn_uint.address == address(bytes20("01234567890123456789"))); + assert(storageStruct[0].fn_uint.selector == bytes4("abcd")); + assert(storageStruct[1].fn_uint.address == address(bytes20("98765432109876543210"))); + assert(storageStruct[1].fn_uint.selector == bytes4("efgh")); + return true; + } +} +// ==== +// compileViaYul: true +// ---- +// test((function)[]): 0x20, 2, "01234567890123456789abcd", "98765432109876543210efgh" -> true diff --git a/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_dynamic.sol b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_dynamic.sol new file mode 100644 index 000000000000..31fc898e4a14 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_dynamic.sol @@ -0,0 +1,27 @@ +pragma abicoder v2; +struct S { + function(uint) external fn_uint; + uint256[] arr; +} + +contract C { + S storageStruct; + + function test(S calldata calldataStruct) public returns (bool) { + storageStruct = calldataStruct; + + assert(storageStruct.fn_uint.address == address(bytes20("01234567890123456789"))); + assert(storageStruct.fn_uint.selector == bytes4("abcd")); + assert(storageStruct.arr.length == 3); + assert(storageStruct.arr[0] == 11); + assert(storageStruct.arr[1] == 22); + assert(storageStruct.arr[2] == 33); + return true; + } +} +// ---- +// test((function,uint256[])): 0x20, "01234567890123456789abcd", 0x40, 3, 11, 22, 33 -> true +// gas irOptimized: 134866 +// gas legacy: 137443 +// gas legacyOptimized: 135246 +// gas ssaCFGOptimized: 134897 diff --git a/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_invalid.sol b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_invalid.sol new file mode 100644 index 000000000000..6aca3ffa8e32 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_invalid.sol @@ -0,0 +1,17 @@ +pragma abicoder v2; +struct S { + function(uint) external fn_uint; +} + +contract C { + S storageStruct; + + function test(S calldata calldataStruct) public returns (bool) { + storageStruct = calldataStruct; + return true; + } +} +// ---- +// test((function)): "01234567890123456789abcd" -> true +// test((function)): 0x3031323334353637383930313233343536373839616263640000000000000001 -> FAILURE +// test((function)): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE diff --git a/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_packed.sol b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_packed.sol new file mode 100644 index 000000000000..2921c585f58b --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_calldata_to_storage_external_function_type_member_packed.sol @@ -0,0 +1,20 @@ +pragma abicoder v2; +struct S { + function(uint) external fn_uint; + uint64 packed; +} + +contract C { + S storageStruct; + + function test(S calldata calldataStruct) public returns (bool) { + storageStruct = calldataStruct; + + assert(storageStruct.fn_uint.address == address(bytes20("01234567890123456789"))); + assert(storageStruct.fn_uint.selector == bytes4("abcd")); + assert(storageStruct.packed == 42); + return true; + } +} +// ---- +// test((function,uint64)): "01234567890123456789abcd", 42 -> true diff --git a/test/libsolidity/semanticTests/structs/copy_to_mapping.sol b/test/libsolidity/semanticTests/structs/copy_to_mapping.sol index 94b744d26373..df9a5590299d 100644 --- a/test/libsolidity/semanticTests/structs/copy_to_mapping.sol +++ b/test/libsolidity/semanticTests/structs/copy_to_mapping.sol @@ -61,6 +61,6 @@ contract C { // gas ssaCFGOptimized: 122611 // from_calldata((bytes,uint16[],uint16)): 0x20, 0x60, 0xa0, 21, 3, 0x666F6F0000000000000000000000000000000000000000000000000000000000, 2, 13, 14 -> 0x20, 0x60, 0xa0, 21, 3, 0x666f6f0000000000000000000000000000000000000000000000000000000000, 2, 13, 14 // gas irOptimized: 114824 -// gas legacy: 118207 +// gas legacy: 118199 // gas legacyOptimized: 115327 // gas ssaCFGOptimized: 114700 diff --git a/test/libsolidity/semanticTests/structs/struct_copy_calldata_to_storage_nested_dynamic_array_v2.sol b/test/libsolidity/semanticTests/structs/struct_copy_calldata_to_storage_nested_dynamic_array_v2.sol index 98a312f3ecb0..8ea676d91e98 100644 --- a/test/libsolidity/semanticTests/structs/struct_copy_calldata_to_storage_nested_dynamic_array_v2.sol +++ b/test/libsolidity/semanticTests/structs/struct_copy_calldata_to_storage_nested_dynamic_array_v2.sol @@ -17,6 +17,6 @@ contract C { // ---- // f(uint32,(uint128,uint256[][2],uint32)): 55, 0x40, 77, 0x60, 88, 0x40, 0x40, 2, 1, 2 -> 55, 77, 1, 2, 88 // gas irOptimized: 202902 -// gas legacy: 207376 +// gas legacy: 207360 // gas legacyOptimized: 203583 // gas ssaCFGOptimized: 202897 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol index 0815a2da7ace..869e75896da1 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol @@ -24,7 +24,7 @@ contract C { // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> // gas irOptimized: 44237 -// gas legacy: 47154 +// gas legacy: 47122 // gas legacyOptimized: 44982 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 // g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3