Skip to content

Panic at compile.rs:78 "content not found" when using parent-relative remappings (../) with libraries that have internal imports #1068

@doocho

Description

@doocho

Description

Aderyn 0.6.8 panics with content not found at aderyn_driver/src/compile.rs:78 when analyzing projects that use parent-relative remappings (e.g., ../dependencies/...) and the remapped library contains internal relative imports (e.g., ./IERC20.sol, ../../utils/Context.sol).

This is a common pattern in Foundry monorepos managed by Soldeer, where dependencies are installed at the workspace root and subprojects reference them via ../dependencies/.

Root Cause

At compile.rs:78:

let content = sources.get(&source_path).expect("content not found");

The sources map (solc input) and sources_ast map (solc output) use different path representations when ../ is involved. When solc resolves a remapping like @openzeppelin/contracts/=../dependencies/@openzeppelin-contracts-5.5.0/ and then follows an internal relative import (e.g., import {Context} from "../../utils/Context.sol"), the resulting canonical path in sources_ast doesn't match the key registered in sources.

Reproduction

I verified the following 4 test cases to isolate the exact trigger:

# Remapping path Library internal imports Result
1 ../dependencies/ (parent) Yes (OpenZeppelin) CRASH
2 ../dependencies/ (parent) No (Solady CREATE3) OK
3 dependencies/ (local) Yes (OpenZeppelin) OK
4 ../dependencies/ (parent) Yes (Solady OwnableRoles) CRASH

The crash requires BOTH conditions: parent-relative path (../) in remapping AND internal relative imports within the library. Either condition alone works fine.

Minimal reproduction (Test case #1 — CRASH)

repro/
├── dependencies/
│   └── @openzeppelin-contracts-5.5.0/   # OpenZeppelin v5.5.0+
└── subproject/
    ├── foundry.toml
    └── src/
        └── Token.sol

subproject/src/Token.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.34;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Token is ERC20 {
    constructor() ERC20("Test", "TST") {
        _mint(msg.sender, 1_000_000e18);
    }
}

subproject/foundry.toml:

[profile.default]
src = "src"
libs = ["lib", "../dependencies"]
auto_detect_remappings = false
solc_version = "0.8.34"
evm_version = "osaka"
remappings = [
    "@openzeppelin/contracts/=../dependencies/@openzeppelin-contracts-5.5.0/",
    "forge-std/=../dependencies/forge-std-1.14.0/src/",
]
cd subproject
forge build   # succeeds
aderyn .       # CRASH: compile.rs:78 "content not found"

Control case #2 — OK (no internal imports)

Same ../dependencies/ remapping but with Solady's CREATE3.sol which has zero imports:

import {CREATE3} from "solady/utils/CREATE3.sol";
remappings = ["solady/=../dependencies/solady-0.1.19/src/"]

Works fine — no internal imports means solc doesn't resolve any additional relative paths.

Control case #3 — OK (local path)

Same OpenZeppelin import but with dependencies/ in the same directory (no ../):

remappings = ["@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.5.0/"]

Works fine — without ../, solc's path resolution stays within the project root.

Control case #4 — CRASH (Solady with internal imports)

Solady's OwnableRoles.sol (which imports ./Ownable.sol) with ../dependencies/:

import {OwnableRoles} from "solady/auth/OwnableRoles.sol";
remappings = ["solady/=../dependencies/solady-0.1.19/src/"]

CRASH — confirms this is NOT OpenZeppelin-specific. Any library with internal imports triggers it.

Output

Ingesting 1 compiled files [solc : v0.8.34]
error: Fatal compiler bug!

Panic: aderyn_driver/src/compile.rs:78
	content not found
Aderyn version: 0.6.8

Note: forge build succeeds for all 4 cases. The issue is only with aderyn's source path resolution.

Environment

  • Aderyn version: 0.6.8 (latest as of 2025-04-03, installed via Homebrew)
  • Forge version: 1.3.5-stable
  • Solc version: 0.8.34
  • OS: macOS 26.2 (Apple Silicon, arm64)
  • EVM version: osaka (also reproducible with cancun)

Impact

This affects all Foundry monorepos using Soldeer where subprojects reference shared dependencies via ../dependencies/. In our case, 10 out of 11 subprojects failed (all except one that only used self-contained libraries with no internal imports).

Workaround

  1. forge flatten: Inline all dependencies into a single file before running aderyn. This works but loses file-level granularity and introduces false positives from library code.
  2. Copy dependencies locally: Move dependencies/ into each subproject so remappings don't need ../.

Suggested Fix

In compile.rs, canonicalize paths before the sources.get(&source_path) lookup — e.g., resolve .. segments via std::fs::canonicalize() or manual path normalization on both the sources HashMap keys and the source_path from sources_ast. This would ensure that subproject/../dependencies/lib/foo.sol and dependencies/lib/foo.sol match as the same key.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions