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.28k stars 966 forks source link

Fails to parse certain tuple assignments #306

Open arxenix opened 5 years ago

arxenix commented 5 years ago

Slither fails to parse certain tuple assignment expressions such as: (uint y, ) = (1,2);

Traceback (most recent call last):
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\__main__.py", line 586, in main_impl
    (results, number_contracts) = process(filename, args, detector_classes, printer_classes)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\__main__.py", line 51, in process
    **vars(args))
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\slither.py", line 76, in __init__
    self._analyze_contracts()
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\slitherSolc.py", line 255, in _analyze_contracts
    self._analyze_third_part(contracts_to_be_analyzed, libraries)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\slitherSolc.py", line 334, in _analyze_third_part
    self._analyze_variables_modifiers_functions(contract)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\slitherSolc.py", line 374, in _analyze_variables_modifiers_functions
    contract.analyze_content_functions()
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\declarations\contract.py", line 282, in analyze_content_functions
    function.analyze_content()
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\declarations\function.py", line 198, in analyze_content
    self._parse_cfg(body)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\declarations\function.py", line 769, in _parse_cfg
    self._parse_block(cfg, node)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\declarations\function.py", line 750, in _parse_block
    node = self._parse_statement(statement, node)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\declarations\function.py", line 719, in _parse_statement
    node = self._parse_variable_definition(statement, node)
  File "C:\Python37\lib\site-packages\slither_analyzer-0.6.4-py3.7.egg\slither\solc_parsing\declarations\function.py", line 502, in _parse_variable_definition
    src = variable['src']
TypeError: 'NoneType' object is not subscriptable

I believe the only broken case is where you have a partial assignment tuple on the LHS and a tuple literal on the RHS

Xenomega commented 4 years ago

This is a bit different now. The above example will compile and run with slither (though its correctness may not be adequate, not sure). Here is an example of what will analyze without error, and what will throw an exception for more context:

contract NonProblematic {
    function f() public returns(uint) {
        uint x;
        (x, ) = (7, 7);
        return x;
    }
}
contract Problematic {
    function f() public returns(uint) {
        uint x;
        (((x, ), )) = ((7, 7) ,7);
        return x;
    }
}

Exception:

ERROR:root:Traceback (most recent call last):
  File "c:\users\x\documents\github\slither\slither\__main__.py", line 610, in main_impl
    (slither_instances, results_detectors, results_printers, number_contracts) = process_all(filename, args,
  File "c:\users\x\documents\github\slither\slither\__main__.py", line 67, in process_all
    (slither, current_results_detectors, current_results_printers, current_analyzed_count) = process_single(
  File "c:\users\x\documents\github\slither\slither\__main__.py", line 53, in process_single
    slither = Slither(target,
  File "c:\users\x\documents\github\slither\slither\slither.py", line 86, in __init__
    self._parser.analyze_contracts()
  File "c:\users\x\documents\github\slither\slither\solc_parsing\slitherSolc.py", line 345, in analyze_contracts
    self._convert_to_slithir()
  File "c:\users\x\documents\github\slither\slither\solc_parsing\slitherSolc.py", line 489, in _convert_to_slithir
    func.generate_slithir_and_analyze()
  File "c:\users\x\documents\github\slither\slither\core\declarations\function.py", line 1652, in generate_slithir_and_analyze
    node.slithir_generation()
  File "c:\users\x\documents\github\slither\slither\core\cfg\node.py", line 702, in slithir_generation
    self._irs = convert_expression(expression, self)
  File "c:\users\x\documents\github\slither\slither\slithir\convert.py", line 64, in convert_expression
    visitor = ExpressionToSlithIR(expression, node)
  File "c:\users\x\documents\github\slither\slither\visitors\slithir\expression_to_slithir.py", line 103, in __init__
    self._visit_expression(self.expression)
  File "c:\users\x\documents\github\slither\slither\visitors\expression\expression.py", line 95, in _visit_expression
    self._post_visit(expression)
  File "c:\users\x\documents\github\slither\slither\visitors\expression\expression.py", line 265, in _post_visit
    self._post_assignement_operation(expression)
  File "c:\users\x\documents\github\slither\slither\visitors\slithir\expression_to_slithir.py", line 122, in _post_assignement_operation
    operation = convert_assignment(left[idx], right[idx], expression.type, expression.expression_return_type)
  File "c:\users\x\documents\github\slither\slither\visitors\slithir\expression_to_slithir.py", line 72, in convert_assignment
    return Assignment(left, right, return_type)
  File "c:\users\x\documents\github\slither\slither\slithir\operations\assignment.py", line 13, in __init__
    assert is_valid_lvalue(left_variable)
AssertionError