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.34k stars 970 forks source link

Use of casting library causes slither to fail: TMP_784(None) = HIGH_LEVEL_CALL, dest:TMP_783(None), function:i128, arguments:[] #912

Closed 0xalpharush closed 2 years ago

0xalpharush commented 3 years ago

I ran into the same error as #667 when running slither on a contract that uses a casting library.

Traceback (most recent call last):
  File "/slither/lib/python3.8/site-packages/slither/__main__.py", line 723, in main_impl
    ) = process_all(filename, args, detector_classes, printer_classes)
  File "/slither/lib/python3.8/site-packages/slither/__main__.py", line 82, in process_all
    ) = process_single(compilation, args, detector_classes, printer_classes)
  File "/slither/lib/python3.8/site-packages/slither/__main__.py", line 65, in process_single
    slither = Slither(target, ast_format=ast, **vars(args))
  File "/slither/lib/python3.8/site-packages/slither/slither.py", line 107, in __init__
    parser.analyze_contracts()
  File "/slither/lib/python3.8/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 391, in analyze_contracts
    self._convert_to_slithir()
  File "/slither/lib/python3.8/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 568, in _convert_to_slithir
    func.generate_slithir_and_analyze()
  File "/slither/lib/python3.8/site-packages/slither/core/declarations/function.py", line 1669, in generate_slithir_and_analyze
    node.slithir_generation()
  File "/slither/lib/python3.8/site-packages/slither/core/cfg/node.py", line 714, in slithir_generation
    self._find_read_write_call()
  File "/slither/lib/python3.8/site-packages/slither/core/cfg/node.py", line 905, in _find_read_write_call
    raise SlitherException(
slither.exceptions.SlitherException: Function not found on TMP_784(None) = HIGH_LEVEL_CALL, dest:TMP_783(None), function:i128, arguments:[]  . Please try compiling with a recent Solidity version. 'NoneType' object has no attribute 'type'
ERROR:root:Error:
ERROR:root:Function not found on TMP_784(None) = HIGH_LEVEL_CALL, dest:TMP_783(None), function:i128, arguments:[]  . Please try compiling with a recent Solidity version. 'NoneType' object has no attribute 'type'

Library

library CastU128I128 {
    /// @dev Safely cast an uint128 to an int128
    function i128(uint128 x) internal pure returns (int128 y) {
        require (x <= uint128(type(int128).max), "Cast overflow");
        y = int128(x);
    }
}

Example usage

contract Example {
    using CastU128I128 for uint128;
    int128 foo = bar.i128();
}

I was able to bypass this by checking that ir.destination.type is not None in core/cfg/node.py, but I don't imagine this is an acceptable fix. https://github.com/crytic/slither/blob/master/slither/core/cfg/node.py#L902

elif ir.destination.type is not None:
    try:
        self._high_level_calls.append((ir.destination.type.type, ir.function))
    except AttributeError as error:
        #  pylint: disable=raise-missing-from
        raise SlitherException(
            f"Function not found on {ir.function_name}. Please try compiling with a recent Solidity version. {error}"
        )

It was helpful to add ir.function_name to the error message for debugging as the temporary name is arbitrary.

except AttributeError as error:
    #  pylint: disable=raise-missing-from
    raise SlitherException(
        f"Function not found on {ir.function_name}. Please try compiling with a recent Solidity version. {error}"
    )

I'm not sure what would be involved in fixing this, but I will give it a shot if a maintainer could provide insight.

montyly commented 3 years ago

Hi @0xalpharush .

Thank you for reporting this. What version of solc and slither are you using? (solc --version, slither --version)

When I run Slither 0.8.0, with solc 0.7.6 or solc 0.8.0, I don't have the issue on:

library CastU128I128 {
    /// @dev Safely cast an uint128 to an int128
    function i128(uint128 x) internal pure returns (int128 y) {
        require (x <= uint128(type(int128).max), "Cast overflow");
        y = int128(x);
    }
}

contract Example {
    using CastU128I128 for uint128;

    function f(uint128 bar) public{
        int128 foo = bar.i128();
    }   
}
0xalpharush commented 3 years ago

@montyly These results are with Slither 0.8.0 and solc 0.8.1 but I confirmed the error on solc 0.8.0 as well. The example I gave is poor for which I apologize; it works in isolation but didn't work when running slither on the entire repo where this pattern is implemented. I confirmed the function i128 is the cause of the error by adding {ir.function_name} to the exception output as I noted above.

You can find the contracts here: https://github.com/code-423n4/2021-08-yield/tree/main/contracts

montyly commented 3 years ago

Thanks @0xalpharush. I can reproduce the bug locally, and I will look into it

mds1 commented 2 years ago

Hey @montyly, curious if this was ever resolved. I'm seeing the same thing when running slither v0.8.1 against this repo: https://github.com/code-423n4/2021-11-malt

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/slither/core/cfg/node.py", line 902, in _find_read_write_call
    self._high_level_calls.append((ir.destination.type.type, ir.function))
AttributeError: 'NoneType' object has no attribute 'type'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/slither/__main__.py", line 741, in main_impl
    ) = process_all(filename, args, detector_classes, printer_classes)
  File "/usr/local/lib/python3.9/site-packages/slither/__main__.py", line 83, in process_all
    ) = process_single(compilation, args, detector_classes, printer_classes)
  File "/usr/local/lib/python3.9/site-packages/slither/__main__.py", line 66, in process_single
    slither = Slither(target, ast_format=ast, **vars(args))
  File "/usr/local/lib/python3.9/site-packages/slither/slither.py", line 107, in __init__
    parser.analyze_contracts()
  File "/usr/local/lib/python3.9/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 393, in analyze_contracts
    self._convert_to_slithir()
  File "/usr/local/lib/python3.9/site-packages/slither/solc_parsing/slither_compilation_unit_solc.py", line 570, in _convert_to_slithir
    func.generate_slithir_and_analyze()
  File "/usr/local/lib/python3.9/site-packages/slither/core/declarations/function.py", line 1676, in generate_slithir_and_analyze
    node.slithir_generation()
  File "/usr/local/lib/python3.9/site-packages/slither/core/cfg/node.py", line 714, in slithir_generation
    self._find_read_write_call()
  File "/usr/local/lib/python3.9/site-packages/slither/core/cfg/node.py", line 905, in _find_read_write_call
    raise SlitherException(
slither.exceptions.SlitherException: Function not found on TMP_4873(None) = HIGH_LEVEL_CALL, dest:REF_2187(None), function:add, arguments:['balance']  . Please try compiling with a recent Solidity version. 'NoneType' object has no attribute 'type'
Error:
Function not found on TMP_4873(None) = HIGH_LEVEL_CALL, dest:REF_2187(None), function:add, arguments:['balance']  . Please try compiling with a recent Solidity version. 'NoneType' object has no attribute 'type'