Fixed a ICE on calldata to struct member copy

This commit is contained in:
hrkrshnn 2022-01-24 11:56:27 +01:00
parent ef8911a629
commit 0fe5811459
8 changed files with 262 additions and 2 deletions

View File

@ -18,6 +18,7 @@ Bugfixes:
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables.
* IR Generator: Add missing cleanup during the conversion of fixed bytes types to smaller fixed bytes types.
* IR Generator: Add missing cleanup for indexed event arguments of value type.
* IR Generator: Fix internal error when copying reference types in calldata and storage to struct or array members in memory.
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
* 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.

View File

@ -2985,8 +2985,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); },

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,96 @@
pragma abicoder v2;
struct S { uint value; }
contract Test {
S[][] a;
S[] b;
constructor() {
a.push();
a[0].push(S(1));
a[0].push(S(2));
a[0].push(S(3));
b.push(S(4));
b.push(S(5));
b.push(S(6));
b.push(S(7));
}
function test1() external returns (bool) {
a.push();
a[1] = b;
assert(a.length == 2);
assert(a[0].length == 3);
assert(a[1].length == 4);
assert(a[1][0].value == 4);
assert(a[1][1].value == 5);
assert(a[1][2].value == 6);
assert(a[1][3].value == 7);
return true;
}
function test2() external returns (bool) {
S[][] memory temp = new S[][](2);
temp = a;
assert(temp.length == 2);
assert(temp[0].length == 3);
assert(temp[1].length == 4);
assert(temp[1][0].value == 4);
assert(temp[1][1].value == 5);
assert(temp[1][2].value == 6);
assert(temp[1][3].value == 7);
return true;
}
function test3() external returns (bool) {
S[][] memory temp = new S[][](2);
temp[0] = a[0];
temp[1] = a[1];
assert(temp.length == 2);
assert(temp[0].length == 3);
assert(temp[1].length == 4);
assert(temp[1][0].value == 4);
assert(temp[1][1].value == 5);
assert(temp[1][2].value == 6);
assert(temp[1][3].value == 7);
return true;
}
function test4() external returns (bool) {
S[][] memory temp = new S[][](2);
temp[0] = a[0];
temp[1] = b;
assert(temp.length == 2);
assert(temp[0].length == 3);
assert(temp[1].length == 4);
assert(temp[1][0].value == 4);
assert(temp[1][1].value == 5);
assert(temp[1][2].value == 6);
assert(temp[1][3].value == 7);
return true;
}
}
// ====
// EVMVersion: >homestead
// compileViaYul: also
// ----
// test1() -> true
// gas irOptimized: 150618
// gas legacy: 150266
// gas legacyOptimized: 149875
// test2() -> true
// test3() -> true
// test4() -> true

View File

@ -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

View File

@ -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

View File

@ -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];
}
}