foundry-rs / foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
https://getfoundry.sh
Apache License 2.0
8.25k stars 1.73k forks source link

forge build sometimes fails to report which file resulted "Stack too deep #8342

Closed hellwolf closed 3 months ago

hellwolf commented 3 months ago

Component

Forge

Have you ensured that all of these are up to date?

What version of Foundry are you on?

forge 0.2.0 (20b3da1 2024-07-02T00:18:52.435480726Z)

What command(s) is the bug in?

forge build

Operating System

Linux

Describe the bug

$ cat .gitmodules 
[submodule "lib/forge-std"]
    path = lib/forge-std
    url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
    path = lib/openzeppelin-contracts
    url = https://github.com/OpenZeppelin/openzeppelin-contracts
$ cat foundry.toml 
[profile.default]
src = "src"
out = "out"
solc_version = "0.8.26"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
$ cat src/BreakSolc0826.sol 
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

library BreakSolc0826 {
    using Strings for uint256;

    function testTokenURIIsExpected(ERC20 token) external view returns (string memory) {
        int96 flowRate = 42069;
        address flowSender = address(1);
        address flowReceiver = address(2);

        return string(
                      abi.encodePacked(
                                       "https://nft.superfluid.finance/cfa/v2/getmeta?flowRate=",
                                       uint256(uint96(flowRate)).toString(),
                                       "&outgoing=true",
                                       "&token_address=",
                                       Strings.toHexString(uint256(uint160(address(42))), 20),
                                       "&chain_id=",
                                       block.chainid.toString(),
                                       "&token_symbol=BORING",
                                       token.symbol(),
                                       "&sender=",
                                       Strings.toHexString(uint256(uint160(flowSender)), 20),
                                       "&receiver=",
                                       Strings.toHexString(uint256(uint160(flowReceiver)), 20),
                                       "&token_decimals=12",
                                       uint256(token.decimals()).toString(),
                                       "&start_date=1" // timestamp shifts 1
                      )
        );
    }
}

Result:

$ forge build
[⠊] Compiling...
[⠒] Compiling 9 files with Solc 0.8.26
[⠢] Solc 0.8.26 finished in 77.84ms
Error: 
Compiler run failed:
Error: Compiler error (/solidity/libyul/backends/evm/AsmCodeGen.cpp:62):Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables. When compiling inline assembly: Variable pos is 2 slot(s) too deep inside the stack. Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables.
CompilerError: Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables. When compiling inline assembly: Variable pos is 2 slot(s) too deep inside the stack. Stack too deep. Try compiling with `--via-ir` (cli) or the equivalent `viaIR: true` (standard JSON) while enabling the optimizer. Otherwise, try removing local variables.

In a larger project, it resulted a situation where such file is very hard to pin point to.

klkvr commented 3 months ago

"stack too deep" errors are coming from solc, there's not much we can do to understand which file it originates from :/

hellwolf commented 3 months ago

I do remember it was not that difficult to know which file/function resulted this. Am I remembering something wrong?

klkvr commented 3 months ago

It always was kind of random, sometimes it gives guidance and maybe even a pointer to a Solidity function which triggered this, sometimes it shows and exception like this. I think that's because when "stack too deep" is hit later after some optimizations, it's just hard to track which Solidity file the given piece of code corresponds to.

anyway, those are just Solidity internals :/ I'd recommend try excluding some of the project sources through --skip to determine which sources are triggering the "stack too deep"

hellwolf commented 3 months ago

Okay fair. I was basically trying to nail down by skipping files, "--skip" is probably easier to automate the process.