Solidity: InternalCompilerError when returning a struct with a mapping from a library function

Created on 16 Sep 2020  路  13Comments  路  Source: ethereum/solidity

Description

Received InternalCompilerError without any description when we are trying to pass a struct to a function as a memory argument (using ABIEncoderV2) and the struct contains a mapping in it. Although, passing a mapping to a function is not allowed by design, i think to have an InternalCompilerError without any description is a real issue indeed.

Environment

  • Compiler version: 0.6.12
  • Target EVM version (as per compiler settings): default
  • Framework/IDE (e.g. Truffle or Remix): both Truffle and Remix
  • EVM execution environment / backend / blockchain client:
  • Operating system:

Steps to Reproduce

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.12 <0.7.0;
pragma experimental ABIEncoderV2;

library TestModel0 {
    struct Data {
        mapping (uint => uint) d;
    }

    function addData(Data storage self, Data memory _data) public {
        /* any code here */
    }
}

Screenshot from 2020-09-16 10-09-01

annoys users bug should compile without error

Most helpful comment

Smaller example:

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.1;
pragma experimental ABIEncoderV2;

library TestLibrary {
    struct Items {
        mapping (uint => uint) a;
    }

    function get() public returns (Items storage x) {
        assembly { x.slot := 0 }
    }
}

contract TestContract {
    function testFunction() public {
        TestLibrary.get();
    }
}

All 13 comments

I think this ICE is valid only for pragma solidity <0.7.0; The ICE goes away for pragma solidity >0.7.0;

I think this ICE is valid only for pragma solidity <0.7.0; The ICE goes away for pragma solidity >0.7.0;

Thanks for your reply. May i know if there is any chance to have this fix in 0.6.x or even earlier versions?

unfortunately, i still encounter an InternalCompilerError (with no description) in 0.7.1 when i have a get function, which outputs a storage, in the above library and use another contract to import the library and call that get function.

Can you provide an example for the above scenario?

Can you provide an example for the above scenario?

try to compile the following code in Remix, solc 0.7.1

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;

library TestLibrary {
    struct Items {
        mapping (uint => uint) a;
    }

    struct Data {
        mapping (uint => Items) d;
    }

    function get(Data storage self, uint _key) public returns (Items storage) {
        return self.d[_key];
    }
}

contract TestContract {

    using TestLibrary for TestLibrary.Data;
    TestLibrary.Data s_data;

    function testFunction(uint _key) public {
        // The following 2 lines are expected to do the same thing...
        // TestLibrary.Items storage _items_1 = s_data.get(1);     // Uncomment this line will give InternalCompilerError:
        TestLibrary.Items storage _items_2 = s_data.d[1];          
    }
}

thanks a lot for the help there.

Smaller example:

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.1;
pragma experimental ABIEncoderV2;

library TestLibrary {
    struct Items {
        mapping (uint => uint) a;
    }

    function get() public returns (Items storage x) {
        assembly { x.slot := 0 }
    }
}

contract TestContract {
    function testFunction() public {
        TestLibrary.get();
    }
}

Yeah the above scenario seems like a bug. ICE gets generated when compiling the above code using SMTEncoder.

/solidity/libsolidity/ast/Types.cpp(2337):Throw in function virtual bool 
solidity::frontend::StructType::isDynamicallyEncoded() const Dynamic exception type: 
boost::wrapexcept<solidity::langutil::InternalCompilerError>
std::exception::what: 
[solidity::util::tag_comment*] =

Yeah the above scenario seems like a bug. ICE gets generated when compiling the above code using SMTEncoder.

/solidity/libsolidity/ast/Types.cpp(2337):Throw in function virtual bool 

solidity::frontend::StructType::isDynamicallyEncoded() const Dynamic exception type: 

boost::wrapexcept<solidity::langutil::InternalCompilerError>

std::exception::what: 

[solidity::util::tag_comment*] =

Thanks for confirming.
Any work around for the moment?

Yeah. Thanks for mentioning the issue :)

As a workaround, you could pass it over as a different type (a struct with a single integer member, for example) and then use inline assembly on both sides to change the type...

As a workaround, you could pass it over as a different type (a struct with a single integer member, for example) and then use inline assembly on both sides to change the type...

not quite familiar with the inline assembly, any hope to have some more hints on that?
thanks.

Fuzzer eventually turns this up, too. Not a fuzz-blocker, per se, but a false positive (well, dup) that has to be inspected from time to time.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

VoR0220 picture VoR0220  路  4Comments

walter-weinmann picture walter-weinmann  路  4Comments

axic picture axic  路  3Comments

madvas picture madvas  路  3Comments

chriseth picture chriseth  路  3Comments