crytic / slither

Static Analyzer for Solidity and Vyper
https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/
GNU Affero General Public License v3.0
5.27k stars 964 forks source link

[Bug-Candidate]: Fails to parse structs outside of library #1379

Closed kevzettler closed 1 year ago

kevzettler commented 2 years ago

Describe the issue:

I run slither . and get a python stack trace containing errors listed below.

Code example to reproduce the issue:

slither.config.json

{
  "hardhat_artifacts_directory": "build/contracts"
}

Version:

kevzettler@kevs-mbp-3 contracts % slither --version
0.8.3

Relevant log output:

kevzettler@kevs-mbp-3 contracts % slither .
'npx hardhat compile --force' running
Generating typings for: 50 artifacts in dir: ./build/typechain for target: ethers-v5
Successfully generated 150 typings!
Compiled 33 Solidity files successfully

(node:73260) ExperimentalWarning: stream/web is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.10/site-packages/slither/__main__.py", line 744, in main_impl
    ) = process_all(filename, args, detector_classes, printer_classes)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/__main__.py", line 87, in process_all
    ) = process_single(compilation, args, detector_classes, printer_classes)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/__main__.py", line 70, in process_single
    slither = Slither(target, ast_format=ast, **vars(args))
  File "/opt/homebrew/lib/python3.10/site-packages/slither/slither.py", line 118, in __init__
    parser.parse_contracts()
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 485, in parse_contracts
    self._analyze_second_part(contracts_to_be_analyzed, libraries)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 553, in _analyze_second_part
    self._analyze_top_level_structures()
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 631, in _analyze_top_level_structures
    struct.analyze()
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/declarations/structure_top_level.py", line 57, in analyze
    elem_parser.analyze(self)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/variables/variable_declaration.py", line 210, in analyze
    self._variable.type = parse_type(self._elem_to_parse, caller_context)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/solidity_types/type_parsing.py", line 414, in parse_type
    mappingTo = parse_type(t["valueType"], next_context)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/solidity_types/type_parsing.py", line 400, in parse_type
    length = parse_expression(t["length"], caller_context)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/expressions/expression_parsing.py", line 255, in parse_expression
    assert isinstance(caller_context, CallerContextExpression)
AssertionError
None
Error in .
Traceback (most recent call last):
  File "/opt/homebrew/lib/python3.10/site-packages/slither/__main__.py", line 744, in main_impl
    ) = process_all(filename, args, detector_classes, printer_classes)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/__main__.py", line 87, in process_all
    ) = process_single(compilation, args, detector_classes, printer_classes)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/__main__.py", line 70, in process_single
    slither = Slither(target, ast_format=ast, **vars(args))
  File "/opt/homebrew/lib/python3.10/site-packages/slither/slither.py", line 118, in __init__
    parser.parse_contracts()
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 485, in parse_contracts
    self._analyze_second_part(contracts_to_be_analyzed, libraries)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 553, in _analyze_second_part
    self._analyze_top_level_structures()
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 631, in _analyze_top_level_structures
    struct.analyze()
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/declarations/structure_top_level.py", line 57, in analyze
    elem_parser.analyze(self)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/variables/variable_declaration.py", line 210, in analyze
    self._variable.type = parse_type(self._elem_to_parse, caller_context)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/solidity_types/type_parsing.py", line 414, in parse_type
    mappingTo = parse_type(t["valueType"], next_context)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/solidity_types/type_parsing.py", line 400, in parse_type
    length = parse_expression(t["length"], caller_context)
  File "/opt/homebrew/lib/python3.10/site-packages/slither/solc_parsing/expressions/expression_parsing.py", line 255, in parse_expression
    assert isinstance(caller_context, CallerContextExpression)
AssertionError
0xalpharush commented 2 years ago

Can you share your code or an example to reproduce this?

If you have similar code to this issue, you can try moving the struct into the contract.

kevzettler commented 2 years ago

Hi @0xalpharush you can reproduce with the following chain of shell commands. This assumes you have git, yarn and slither installed

git clone --single-branch --branch slither-v2.5.0 https://github.com/kevzettler/semaphore && \
cd semaphore && \ 
yarn && \ 
cd packages/contracts && \
slither .
kevzettler commented 1 year ago

I have confirmed that this parsing failure was due to a scenario where a shared library had a struct defined outside of it like:

struct SharedStruct{}
library SharedLibrary{}

contract Testcontract{
    using SharedLibrary for SharedStruct;
}

If I modify it to nest the struct within the library like:

library SharedLibrary{
    struct SharedStruct{}
}

contract Testcontract{
    using SharedLibrary for SharedLibrary.SharedStruct;
}

slither is able to parse.