Skip to content

Commit

Permalink
Fixed a ICE on calldata to struct member copy
Browse files Browse the repository at this point in the history
  • Loading branch information
hrkrshnn committed Jan 26, 2022
1 parent 3f401eb commit e485450
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Changelog.md
Expand Up @@ -16,7 +16,8 @@ Bugfixes:
* Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``.
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables.
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
* IR Generator: Fix IR syntax error when copying reference types in calldata and storage to struct members in memory.
* Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different.
* TypeChecker: Fix ICE when a constant variable declaration forward references a struct.

Expand Down
7 changes: 5 additions & 2 deletions libsolidity/codegen/ir/IRGeneratorForStatements.cpp
Expand Up @@ -2982,8 +2982,11 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
{
solAssert(_lvalue.type.sizeOnStack() == 1);
auto const* valueReferenceType = dynamic_cast<ReferenceType const*>(&_value.type());
solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory));
appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
solAssert(valueReferenceType);
if (valueReferenceType->dataStoredIn(DataLocation::Memory))
appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n";
else
appendCode() << "mstore(" + _memory.address + ", " + m_utils.conversionFunction(_value.type(), _lvalue.type) + "(" + _value.commaSeparatedList() + "))\n";
}
},
[&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); },
Expand Down
38 changes: 38 additions & 0 deletions test/libsolidity/semanticTests/structs/copy_from_calldata.sol
@@ -0,0 +1,38 @@
// Example from https://github.com/ethereum/solidity/issues/12558
pragma abicoder v2;
contract C {
function f(uint[] calldata a) external returns (uint[][] memory) {
uint[][] memory m = new uint[][](2);
m[0] = a;

return m;
}
}
contract Test {
C immutable c = new C();

function test() external returns (bool) {
uint[] memory arr = new uint[](4);

arr[0] = 13;
arr[1] = 14;
arr[2] = 15;
arr[3] = 16;

uint[][] memory ret = c.f(arr);
assert(ret.length == 2);
assert(ret[0].length == 4);
assert(ret[0][0] == 13);
assert(ret[0][1] == 14);
assert(ret[0][2] == 15);
assert(ret[0][3] == 16);
assert(ret[1].length == 0);

return true;
}
}
// ====
// EVMVersion: >homestead
// compileViaYul: also
// ----
// test() -> true
24 changes: 24 additions & 0 deletions test/libsolidity/semanticTests/structs/copy_from_storage.sol
@@ -0,0 +1,24 @@
pragma abicoder v2;
// Example from https://github.com/ethereum/solidity/issues/12558
struct S {
uint x;
}

contract C {
S sStorage;
constructor() {
sStorage.x = 13;
}

function f() external returns (S[] memory) {
S[] memory sMemory = new S[](1);

sMemory[0] = sStorage;

return sMemory;
}
}
// ====
// compileViaYul: also
// ----
// f() -> 0x20, 1, 13
44 changes: 44 additions & 0 deletions test/libsolidity/semanticTests/structs/function_type_copy.sol
@@ -0,0 +1,44 @@
pragma abicoder v2;
struct S {
function () external[] functions;
}

contract C {
function f(function () external[] calldata functions) external returns (S memory) {
S memory s;
s.functions = functions;
return s;
}
}

contract Test {
C immutable c = new C();

function test() external returns (bool) {
function() external[] memory functions = new function() external[](3);

functions[0] = this.random1;
functions[1] = this.random2;
functions[2] = this.random3;

S memory ret = c.f(functions);

assert(ret.functions.length == 3);
assert(ret.functions[0] == this.random1);
assert(ret.functions[1] == this.random2);
assert(ret.functions[2] == this.random3);

return true;
}
function random1() external {
}
function random2() external {
}
function random3() external {
}
}
// ====
// EVMVersion: >homestead
// compileViaYul: also
// ----
// test() -> true
@@ -0,0 +1,45 @@
pragma abicoder v2;

struct St0 {
bytes el0;
}
contract C {
function f() external returns (St0 memory) {
St0 memory x;
x.el0 = msg.data;
return x;
}

function g() external returns (St0 memory) {
bytes memory temp = msg.data;
St0 memory x;
x.el0 = temp;
return x;
}

function hashes() external returns (bytes4, bytes4) {
return (this.f.selector, this.g.selector);
}

function large(uint256, uint256, uint256, uint256) external returns (St0 memory) {
St0 memory x;
x.el0 = msg.data;
return x;
}

function another_large(uint256, uint256, uint256, uint256) external returns (St0 memory) {
bytes memory temp = msg.data;
St0 memory x;
x.el0 = temp;
return x;
}

}
// ====
// compileViaYul: also
// ----
// f() -> 0x20, 0x20, 4, 0x26121ff000000000000000000000000000000000000000000000000000000000
// g() -> 0x20, 0x20, 4, 0xe2179b8e00000000000000000000000000000000000000000000000000000000
// hashes() -> 0x26121ff000000000000000000000000000000000000000000000000000000000, 0xe2179b8e00000000000000000000000000000000000000000000000000000000
// large(uint256,uint256,uint256,uint256): 1, 2, 3, 4 -> 0x20, 0x20, 0x84, 0xe02492f800000000000000000000000000000000000000000000000000000000, 0x100000000000000000000000000000000000000000000000000000000, 0x200000000000000000000000000000000000000000000000000000000, 0x300000000000000000000000000000000000000000000000000000000, 0x400000000000000000000000000000000000000000000000000000000
// another_large(uint256,uint256,uint256,uint256): 1, 2, 3, 4 -> 0x20, 0x20, 0x84, 0x2a46f85a00000000000000000000000000000000000000000000000000000000, 0x100000000000000000000000000000000000000000000000000000000, 0x200000000000000000000000000000000000000000000000000000000, 0x300000000000000000000000000000000000000000000000000000000, 0x400000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,9 @@
// Example from https://github.com/ethereum/solidity/issues/12558
pragma abicoder v2;
contract C {
function() external[1][] s0;
constructor(function() external[1][] memory i0)
{
i0[0] = s0[1];
}
}

0 comments on commit e485450

Please sign in to comment.