From fc37b18e884af0ebc245a7a905012a22fb7904a9 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 10 Sep 2021 16:04:49 +0200 Subject: [PATCH] Fix inline assembly assignments to calldata structs and statically-sized arrays. --- Changelog.md | 1 + libsolidity/codegen/ContractCompiler.cpp | 31 +++++++++++++------ ....sol => calldata_array_assign_dynamic.sol} | 0 .../calldata_array_assign_static.sol | 10 ++++++ .../inlineAssembly/calldata_struct_assign.sol | 18 +++++++++++ .../calldata_struct_assign_and_return.sol | 23 ++++++++++++++ 6 files changed, 74 insertions(+), 9 deletions(-) rename test/libsolidity/semanticTests/inlineAssembly/{calldata_array_assign.sol => calldata_array_assign_dynamic.sol} (100%) create mode 100644 test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol diff --git a/Changelog.md b/Changelog.md index 04e443d62..03057b6da 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,7 @@ Compiler Features: Bugfixes: + * Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly. * Code Generator: Use stable source order for ABI functions. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6c5a0abe0..5c51a9bb9 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -860,15 +860,28 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (variable->type()->dataStoredIn(DataLocation::CallData)) { - auto const* arrayType = dynamic_cast(variable->type()); - solAssert( - arrayType && arrayType->isDynamicallySized() && arrayType->dataStoredIn(DataLocation::CallData), - "" - ); - solAssert(suffix == "offset" || suffix == "length", ""); - solAssert(variable->type()->sizeOnStack() == 2, ""); - if (suffix == "length") - stackDiff--; + if (auto const* arrayType = dynamic_cast(variable->type())) + { + if (arrayType->isDynamicallySized()) + { + solAssert(suffix == "offset" || suffix == "length", ""); + solAssert(variable->type()->sizeOnStack() == 2, ""); + if (suffix == "length") + stackDiff--; + } + else + { + solAssert(variable->type()->sizeOnStack() == 1, ""); + solAssert(suffix.empty(), ""); + } + } + else + { + auto const* structType = dynamic_cast(variable->type()); + solAssert(structType, ""); + solAssert(variable->type()->sizeOnStack() == 1, ""); + solAssert(suffix.empty(), ""); + } } else solAssert(suffix.empty(), ""); diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_dynamic.sol similarity index 100% rename from test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign.sol rename to test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_dynamic.sol diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol new file mode 100644 index 000000000..3c0437819 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint[2][2] calldata x) public returns (uint[2][2] memory r) { + assembly { x := 0x24 } + r = x; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256[2][2]): 0x0, 8, 7, 6, 5 -> 8, 7, 6, 5 diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol new file mode 100644 index 000000000..bc8f9ffb7 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol @@ -0,0 +1,18 @@ +pragma abicoder v2; + +contract C { + struct S { uint256 x; } + struct S2 { uint256 x; uint256 y; } + function f(S calldata s, S2 calldata s2) public pure returns (uint256 r, uint256 r2) { + assembly { + s := s2 + s2 := 4 + } + r = s.x; + r2 = s2.x; + } +} +// ==== +// compileViaYul: also +// ---- +// f((uint256),(uint256,uint256)): 0x42, 0x07, 0x77 -> 0x07, 0x42 diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol new file mode 100644 index 000000000..56a67f383 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol @@ -0,0 +1,23 @@ +pragma abicoder v2; +contract C { + struct S { int8 x; int8 y; } + function f() internal pure returns(S calldata s) { + assembly { + s := 0x24 + } + } + function g() public pure returns(int8, int8) { + S calldata s = f(); + return (s.x, s.y); + } + function h() public pure returns(uint256) { f(); return 0x42; } + function i() public pure returns(uint256) { abi.decode(msg.data[4:], (S)); return 0x42; } +} +// ==== +// compileViaYul: also +// ---- +// g(): 0xCAFFEE, 0x42, 0x21 -> 0x42, 0x21 +// g(): 0xCAFFEE, 0x4242, 0x2121 -> FAILURE +// g(): 0xCAFFEE, 0x42 -> 0x42, 0 +// h() -> 0x42 +// i() -> FAILURE