Fix struct type resolution and SSA resilience for complex codebases#2962
Open
Fix struct type resolution and SSA resilience for complex codebases#2962
Conversation
When multiple contracts share the same name (e.g. both files define `abstract contract Structs`), `scope.contracts` dict overwrites one with the other, causing struct lookups via `all_structures` to fail with `ParsingError: Type not found struct ContractName.StructName`. Use `sl.contracts` (full compilation unit) instead of `scope.contracts.values()` to build `all_structures` and `all_enums`, matching the existing approach used for top-level contexts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three classes of issues fixed: 1. SSA handles state variables not in current contract's instances: - get() returns raw StateVariable instead of assertion failure - update_lvalue() skips updates for unknown state variables - last_name() filters to SSA-typed variables, returns None safely - fix_phi_rvalues_and_storage_ref() filters None from rvalues - fix_phi() in Contract skips unknown state variable names - convert_variable_to_non_ssa() accepts raw StateVariable/LocalVariable 2. Per-item error handling prevents one failure from aborting siblings: - analyze_content_functions() catches errors per-function, not per-loop - analyze_content_modifiers() catches errors per-modifier, not per-loop - Expression analysis in analyze_content() catches errors per-node 3. Null safety in ternary rewriting: - Skip nodes with None expressions in _rewrite_ternary_as_if_else() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes multiple crashes when analyzing complex codebases with contract name collisions, deeply inherited state variables, and ternary operators in partially-parsed functions.
Bug 1: Struct Type Resolution with Same-Name Contract Collisions
Root Cause:
FileScope.contractsis adict[str, Contract]keyed by contract name. When a file imports a contract with the same name as a local contract (viaimport { Structs as Alias }), the imported contract silently overwrites the local one. Theparse_type()function intype_parsing.pybuildsall_structuresandall_enumsfromscope.contracts.values(), which loses all structs/enums from the overwritten contract.Fix: Changed
all_structuresandall_enumsto be built fromsl.contracts(the full compilation unit) instead ofscope.contracts.values(). This matches the existing approach already used for top-level contexts and avoids the dict collision entirely.Files:
slither/solc_parsing/solidity_types/type_parsing.pyBug 2: SSA Assertion Failure on Untracked State Variables
Root Cause: The
get()function inssa.pychecksisinstance(variable, StateVariable) and variable.canonical_name in state_variables_instances, but if aReferenceVariable.points_torefers to a state variable not in the current contract's SSA instances (e.g., from an external contract or unresolved due to name collisions), theStateVariablefalls through all handlers and hits an assertion at line 632 whereStateVariableis not listed as an allowed type.Fix: When a
StateVariableis not instate_variables_instances, return it as-is (same treatment asConstant,Contract, etc.). Also hardened all downstream SSA consumers:update_lvalue(): Skip updates for unknown state variableslast_name(): Filter to SSA-typed variables, returnNonewhen no candidates foundfix_phi_rvalues_and_storage_ref(): FilterNonefrom phi rvaluesfix_phi()in Contract: Skip unknown state variable namesconvert_variable_to_non_ssa(): Accept rawStateVariable/LocalVariableFiles:
slither/slithir/utils/ssa.py,slither/core/declarations/contract.py,slither/analyses/data_dependency/data_dependency.pyBug 3: One Parsing Failure Aborts All Sibling Functions
Root Cause:
analyze_content_functions()andanalyze_content_modifiers()wrapped their entire loop in a singletry/except. When one function raisedVariableNotFound(e.g., an unresolvable struct constructor), ALL remaining functions in the contract were skipped — including their ternary rewriting phase. This caused surviving ternary expressions to crash during IR generation.Fix: Moved
try/exceptinside the loop so each function/modifier is independently analyzed. Also added per-node error handling in expression analysis withinanalyze_content()so that a failure in one CFG node doesn't prevent ternary rewriting from running on other nodes.Files:
slither/solc_parsing/declarations/contract.py,slither/solc_parsing/declarations/function.pyTest Results
🤖 Generated with Claude Code