Skip to content

Skip on-disk filename verification for standard json sources#686

Open
arpitjain099 wants to merge 1 commit into
crytic:masterfrom
arpitjain099:fix/standard-json-skip-filename-verification
Open

Skip on-disk filename verification for standard json sources#686
arpitjain099 wants to merge 1 commit into
crytic:masterfrom
arpitjain099:fix/standard-json-skip-filename-verification

Conversation

@arpitjain099

Copy link
Copy Markdown

Fixes #495

Problem

When compiling a solc standard json input, parse_standard_json_output calls convert_filename for every source path. convert_filename runs _verify_filename_existence, which requires the path to exist on disk. For standard json, the source keys are virtual: the sources can be provided inline via content, so they often do not map to real files. As a result, a valid standard json compilation raises InvalidCompilation: Unknown file: ....

The issue reporter hits this directly:

from crytic_compile.platform.solc_standard_json import SolcStandardJson
a = SolcStandardJson("compiler.json")
from crytic_compile import CryticCompile
CryticCompile(a)
crytic_compile.platform.exceptions.InvalidCompilation: Unknown file: main.sol

parse_standard_json_output already carried a skip_filename flag, but its if/else branches were identical, so it had no effect.

Fix

  • convert_filename gains an opt-in skip_filename_verification: bool = False parameter. When True it bypasses the on-disk _verify_filename_existence check and keeps the rest of the path normalization unchanged. Default behavior is untouched, so every other platform (solc, hardhat, foundry, etc.) keeps verifying filenames exactly as before.
  • parse_standard_json_output now passes skip_filename_verification=True for both the sources and contracts paths, and the dead identical branches are removed.

Before / after

Reproduction (mocking the solc invocation so no solc binary is needed), source main.sol provided inline and absent from disk:

Before:

RAISED: InvalidCompilation - Unknown file: main.sol

After:

NO ERROR. filenames: ['main.sol']

Tests

  • tests/test_solc_standard_json.py::test_standard_json_does_not_verify_virtual_filenames: end-to-end regression test through CryticCompile(SolcStandardJson(...)) with the solc call mocked. Fails on the current master with InvalidCompilation: Unknown file: main.sol, passes with the fix.
  • tests/test_naming.py: two unit tests for convert_filename, one asserting skip_filename_verification=True returns a Filename for a path absent on disk, one asserting the default still raises InvalidCompilation for a missing file (guards the non-standard-json paths that rely on verification).

All previously passing tests continue to pass. The tests that fail in my environment fail identically on pristine master because they require a real solc binary or network access.

Standard json source paths are virtual keys that can be provided inline
via content, so they need not exist on disk. parse_standard_json_output
called convert_filename, which ran _verify_filename_existence and raised
InvalidCompilation for absent files.

Add an opt-in skip_filename_verification parameter to convert_filename
and pass it on the standard json path. Default behavior is unchanged for
all other platforms. The previous skip_filename branches were dead code
(both arms identical) and are removed.

Fixes crytic#495

Signed-off-by: Arpit Jain <[email protected]>
@elopez

elopez commented Jun 5, 2026

Copy link
Copy Markdown
Member

Hi! Do you have any real-life examples (eg foundry project or similar) where these virtual files are used? I'm trying to understand why is this change needed. Typically the files exist on disk, as you need them for foundry et al to compile your project.

@arpitjain099

Copy link
Copy Markdown
Author

Good question. The case where the source files never exist on disk is standard-json input whose sources are provided inline through the content field rather than urls. A few concrete places this shows up:

  • Etherscan (and Blockscout) "Standard-Json-Input" verified sources: when you fetch a verified contract's source, you get a single standard-json blob with every source embedded under sources.<path>.content. Running crytic-compile / Slither directly on that JSON (a common way to analyze already-deployed, verified contracts) means the paths in the JSON are logical identifiers, not files in the working directory.
  • Hardhat artifacts/build-info/*.json and similar build-info files embed the full Standard JSON input the same way; feeding that input back to crytic-compile re-compiles from the embedded content without the original tree present.
  • Programmatic/API use where the standard-json is assembled in memory (for example a service that receives source text over an API and analyzes it) and never writes the sources to disk.

In all of these the compiler is given the sources via content, so solc resolves them fine, but convert_filename's on-disk existence check rejects the logical path with Unknown file. That is the path this PR skips the verification for (only on the standard-json platform); the non-standard-json platforms still verify as before. Happy to add one of these as a test fixture if that would help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

parse_standard_json_output shall skip filename verification

2 participants