ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.29k stars 5.77k forks source link

Uncaught exception: YUL StackLimitEvader optimizer #14174

Open iVoider opened 1 year ago

iVoider commented 1 year ago

Description

The .yul snippet below

{
            let _1 := memoryguard(1111111111111111111111100)
            mstore(0x40, _1)
            mstore8(add(_1, 31), 200)
            mstore(_1, 300)
            return(_1, add(_1, 100))
}

produces:

Uncaught exception:
/solidity/libyul/optimiser/StackLimitEvader.cpp(183): Throw in function static void solidity::yul::StackLimitEvader::run(solidity::yul::OptimiserStepContext&, solidity::yul::Object&, const std::map<solidity::yul::YulString, std::set<solidity::yul::YulString> >&)
Dynamic exception type: boost::wrapexcept<solidity::yul::YulAssertion>
std::exception::what: Yul assertion failed
[solidity::util::tag_comment*] = Yul assertion failed

when compiled with

solc --strict-assembly --optimize test.yul

Environment

Steps to Reproduce

Description is self-sufficient

bshastry commented 1 year ago

Smaller repro

{
    mstore(40, memoryguard(0x120306708))
    sstore(1, mload(40))
}
ekpyron commented 1 year ago

For the record: we may want to produce better error messages for these cases, but those are all invalid uses of memoryguard: The argument to memoryguard defines the currently assumed start of "general purpose memory", so it will always be a low value - and a value beyond 2^32 for it makes no sense.

But yeah, this should be caught in Yul analysis rather than hit an assertion in Yul codegen.

ekpyron commented 1 year ago

Simplest repo is probably { sstore(0, memoryguard(0x100000000)) }, the sstore only being there to prevent the optimizer from eliminating the memoryguard altogether (otherwise pop(memoryguard(0x100000000)) should even be enough).