Merge remote-tracking branch 'crytic/slither/dev' into dev-upgradeability-utils

# Conflicts:
#	README.md
pull/1757/head
webthethird 2 years ago
commit a6d49d52f3
  1. 2
      .github/workflows/ci.yml
  2. 93
      README.md
  3. 7
      scripts/ci_test_etherscan.sh
  4. 4
      setup.py
  5. 9
      slither/__main__.py
  6. 27
      slither/core/declarations/contract.py
  7. 2
      slither/detectors/functions/cyclomatic_complexity.py
  8. 10
      slither/detectors/shadowing/local.py
  9. 8
      slither/detectors/variables/predeclaration_usage_local.py
  10. 4
      slither/detectors/variables/uninitialized_storage_variables.py
  11. 9
      slither/printers/guidance/echidna.py
  12. 20
      slither/slither.py
  13. 8
      slither/slithir/convert.py
  14. 27
      slither/solc_parsing/declarations/contract.py
  15. 18
      slither/solc_parsing/declarations/using_for_top_level.py
  16. 9
      slither/utils/command_line.py
  17. 11
      slither/utils/type.py
  18. 7
      tests/custom_comments/contract_comment.sol
  19. 10
      tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol
  20. 123
      tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol.0.4.25.LocalShadowing.json
  21. 14
      tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol
  22. 286
      tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol.0.5.16.LocalShadowing.json
  23. 14
      tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol
  24. 286
      tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol.0.6.11.LocalShadowing.json
  25. 14
      tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol
  26. 282
      tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol.0.7.6.LocalShadowing.json
  27. 17
      tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol
  28. 90
      tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol.0.8.19.UninitializedStorageVars.json
  29. 5
      tests/test_detectors.py
  30. 46
      tests/test_features.py
  31. 2
      tests/using-for-global-collision/src/MyTypeA.sol
  32. 4
      tests/using-for-global-collision/src/MyTypeA/Casting.sol
  33. 5
      tests/using-for-global-collision/src/MyTypeA/Math.sol
  34. 6
      tests/using-for-global-collision/src/MyTypeA/Type.sol
  35. 2
      tests/using-for-global-collision/src/MyTypeB.sol
  36. 4
      tests/using-for-global-collision/src/MyTypeB/Casting.sol
  37. 6
      tests/using-for-global-collision/src/MyTypeB/Math.sol
  38. 6
      tests/using-for-global-collision/src/MyTypeB/Type.sol
  39. 7
      tests/using-for-global-collision/src/Test.sol

@ -67,7 +67,7 @@ jobs:
- name: Set up nix - name: Set up nix
if: matrix.type == 'dapp' if: matrix.type == 'dapp'
uses: cachix/install-nix-action@v16 uses: cachix/install-nix-action@v20
- name: Set up cachix - name: Set up cachix
if: matrix.type == 'dapp' if: matrix.type == 'dapp'

@ -5,13 +5,15 @@
[![Slack Status](https://empireslacking.herokuapp.com/badge.svg)](https://empireslacking.herokuapp.com) [![Slack Status](https://empireslacking.herokuapp.com/badge.svg)](https://empireslacking.herokuapp.com)
[![PyPI version](https://badge.fury.io/py/slither-analyzer.svg)](https://badge.fury.io/py/slither-analyzer) [![PyPI version](https://badge.fury.io/py/slither-analyzer.svg)](https://badge.fury.io/py/slither-analyzer)
Slither is a Solidity static analysis framework written in Python 3. It runs a suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly prototype custom analyses. Slither is a Solidity static analysis framework written in Python3. It runs a suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly prototype custom analyses.
- [Features](#features) - [Features](#features)
- [Bugs and Optimizations Detection](#bugs-and-optimizations-detection) - [Usage](#usage)
- [How to Install](#how-to-install)
- [Detectors](#detectors)
- [Printers](#printers) - [Printers](#printers)
- [Tools](#tools) - [Tools](#tools)
- [How to Install](#how-to-install) - [API Documentation](#api-documentation)
- [Getting Help](#getting-help) - [Getting Help](#getting-help)
- [FAQ](#faq) - [FAQ](#faq)
- [Publications](#publications) - [Publications](#publications)
@ -20,35 +22,68 @@ Slither is a Solidity static analysis framework written in Python 3. It runs a s
* Detects vulnerable Solidity code with low false positives (see the list of [trophies](./trophies.md)) * Detects vulnerable Solidity code with low false positives (see the list of [trophies](./trophies.md))
* Identifies where the error condition occurs in the source code * Identifies where the error condition occurs in the source code
* Easily integrates into continuous integration and Truffle builds * Easily integrates into continuous integration and Hardhat/Foundry builds
* Built-in 'printers' quickly report crucial contract information * Built-in 'printers' quickly report crucial contract information
* Detector API to write custom analyses in Python * Detector API to write custom analyses in Python
* Ability to analyze contracts written with Solidity >= 0.4 * Ability to analyze contracts written with Solidity >= 0.4
* Intermediate representation ([SlithIR](https://github.com/trailofbits/slither/wiki/SlithIR)) enables simple, high-precision analyses * Intermediate representation ([SlithIR](https://github.com/trailofbits/slither/wiki/SlithIR)) enables simple, high-precision analyses
* Correctly parses 99.9% of all public Solidity code * Correctly parses 99.9% of all public Solidity code
* Average execution time of less than 1 second per contract * Average execution time of less than 1 second per contract
* Integrates with Github's code scanning in [CI](https://github.com/marketplace/actions/slither-action)
## Usage
## Bugs and Optimizations Detection Run Slither on a Hardhat/Foundry/Dapp/Brownie application:
Run Slither on a Truffle/Embark/Dapp/Etherlime/Hardhat application:
```bash ```bash
slither . slither .
``` ```
This is the preferred option if your project has dependencies as Slither relies on the underlying compilation framework to compile source code.
Run Slither on a single file: However, you can run Slither on a single file that does not import dependencies:
```bash ```bash
slither tests/uninitialized.sol slither tests/uninitialized.sol
``` ```
## How to install
Slither requires Python 3.8+.
If you're **not** going to use one of the [supported compilation frameworks](https://github.com/crytic/crytic-compile), you need [solc](https://github.com/ethereum/solidity/), the Solidity compiler; we recommend using [solc-select](https://github.com/crytic/solc-select) to conveniently switch between solc versions.
### Using Pip
```bash
pip3 install slither-analyzer
```
### Using Git
```bash
git clone https://github.com/crytic/slither.git && cd slither
python3 setup.py install
```
We recommend using a Python virtual environment, as detailed in the [Developer Installation Instructions](https://github.com/trailofbits/slither/wiki/Developer-installation), if you prefer to install Slither via git.
### Using Docker
Use the [`eth-security-toolbox`](https://github.com/trailofbits/eth-security-toolbox/) docker image. It includes all of our security tools and every major version of Solidity in a single image. `/home/share` will be mounted to `/share` in the container.
```bash
docker pull trailofbits/eth-security-toolbox
```
To share a directory in the container:
```bash
docker run -it -v /home/share:/share trailofbits/eth-security-toolbox
```
### Integration ### Integration
- For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action). - For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action).
- To generate a Markdown report, use `slither [target] --checklist`. - To generate a Markdown report, use `slither [target] --checklist`.
- To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`) - To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`)
Use [solc-select](https://github.com/crytic/solc-select) if your contracts require older versions of solc. For additional configuration, see the [usage](https://github.com/trailofbits/slither/wiki/Usage) documentation. ## Detectors
### Detectors
Num | Detector | What it Detects | Impact | Confidence Num | Detector | What it Detects | Impact | Confidence
@ -173,40 +208,8 @@ See the [Tool documentation](https://github.com/crytic/slither/wiki/Tool-Documen
[Contact us](https://www.trailofbits.com/contact/) to get help on building custom tools. [Contact us](https://www.trailofbits.com/contact/) to get help on building custom tools.
## How to install ## API Documentation
Documentation on Slither's internals is available [here](https://crytic.github.io/slither/slither.html).
Slither requires Python 3.8+.
If you're **not** going to use one of the [supported compilation frameworks](https://github.com/crytic/crytic-compile),
you need to have on your machine the right version of [solc](https://github.com/ethereum/solidity/), the Solidity compiler.
### Using Pip
```bash
pip3 install slither-analyzer
```
### Using Git
```bash
git clone https://github.com/crytic/slither.git && cd slither
python3 setup.py install
```
We recommend using a Python virtual environment, as detailed in the [Developer Installation Instructions](https://github.com/trailofbits/slither/wiki/Developer-installation), if you prefer to install Slither via git.
### Using Docker
Use the [`eth-security-toolbox`](https://github.com/trailofbits/eth-security-toolbox/) docker image. It includes all of our security tools and every major version of Solidity in a single image. `/home/share` will be mounted to `/share` in the container.
```bash
docker pull trailofbits/eth-security-toolbox
```
To share a directory in the container:
```bash
docker run -it -v /home/share:/share trailofbits/eth-security-toolbox
```
## Getting Help ## Getting Help

@ -17,12 +17,5 @@ if [ "$GITHUB_ETHERSCAN" = "" ]; then
sleep $(( ( RANDOM % 5 ) + 1 ))s sleep $(( ( RANDOM % 5 ) + 1 ))s
fi fi
echo "::group::Etherscan rinkeby"
if ! slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --etherscan-apikey "$GITHUB_ETHERSCAN" --no-fail-pedantic; then
echo "Etherscan rinkeby test failed"
exit 1
fi
echo "::endgroup::"
exit 0 exit 0

@ -15,8 +15,8 @@ setup(
"packaging", "packaging",
"prettytable>=0.7.2", "prettytable>=0.7.2",
"pycryptodome>=3.4.6", "pycryptodome>=3.4.6",
"crytic-compile>=0.3.0", # "crytic-compile>=0.3.0",
# "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile",
], ],
extras_require={ extras_require={
"dev": [ "dev": [

@ -76,9 +76,6 @@ def process_single(
ast = "--ast-compact-json" ast = "--ast-compact-json"
if args.legacy_ast: if args.legacy_ast:
ast = "--ast-json" ast = "--ast-json"
if args.checklist:
args.show_ignored_findings = True
slither = Slither(target, ast_format=ast, **vars(args)) slither = Slither(target, ast_format=ast, **vars(args))
return _process(slither, detector_classes, printer_classes) return _process(slither, detector_classes, printer_classes)
@ -760,7 +757,7 @@ def main_impl(
# If we are outputting JSON, capture all standard output. If we are outputting to stdout, we block typical stdout # If we are outputting JSON, capture all standard output. If we are outputting to stdout, we block typical stdout
# output. # output.
if outputting_json or output_to_sarif: if outputting_json or outputting_sarif:
StandardOutputCapture.enable(outputting_json_stdout or outputting_sarif_stdout) StandardOutputCapture.enable(outputting_json_stdout or outputting_sarif_stdout)
printer_classes = choose_printers(args, all_printer_classes) printer_classes = choose_printers(args, all_printer_classes)
@ -871,7 +868,9 @@ def main_impl(
# Output our results to markdown if we wish to compile a checklist. # Output our results to markdown if we wish to compile a checklist.
if args.checklist: if args.checklist:
output_results_to_markdown(results_detectors, args.checklist_limit) output_results_to_markdown(
results_detectors, args.checklist_limit, args.show_ignored_findings
)
# Don't print the number of result for printers # Don't print the number of result for printers
if number_contracts == 0: if number_contracts == 0:

@ -110,6 +110,8 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
Dict["StateVariable", Set[Union["StateVariable", "Function"]]] Dict["StateVariable", Set[Union["StateVariable", "Function"]]]
] = None ] = None
self._comments: Optional[str] = None
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region General's properties # region General's properties
@ -165,6 +167,31 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def is_library(self, is_library: bool): def is_library(self, is_library: bool):
self._is_library = is_library self._is_library = is_library
@property
def comments(self) -> Optional[str]:
"""
Return the comments associated with the contract.
When using comments, avoid strict text matching, as the solc behavior might change.
For example, for old solc version, the first space after the * is not kept, i.e:
* @title Test Contract
* @dev Test comment
Returns
- " @title Test Contract\n @dev Test comment" for newest versions
- "@title Test Contract\n@dev Test comment" for older versions
Returns:
the comment as a string
"""
return self._comments
@comments.setter
def comments(self, comments: str):
self._comments = comments
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -22,7 +22,7 @@ class CyclomaticComplexity(AbstractDetector):
IMPACT = DetectorClassification.INFORMATIONAL IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.HIGH CONFIDENCE = DetectorClassification.HIGH
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#cyclomatic-complexity"' WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#cyclomatic-complexity"
WIKI_TITLE = "Cyclomatic complexity" WIKI_TITLE = "Cyclomatic complexity"
WIKI_DESCRIPTION = "Detects functions with high (> 11) cyclomatic complexity." WIKI_DESCRIPTION = "Detects functions with high (> 11) cyclomatic complexity."

@ -57,6 +57,7 @@ contract Bug {
OVERSHADOWED_MODIFIER = "modifier" OVERSHADOWED_MODIFIER = "modifier"
OVERSHADOWED_STATE_VARIABLE = "state variable" OVERSHADOWED_STATE_VARIABLE = "state variable"
OVERSHADOWED_EVENT = "event" OVERSHADOWED_EVENT = "event"
OVERSHADOWED_RETURN_VARIABLE = "return variable"
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
def detect_shadowing_definitions( def detect_shadowing_definitions(
@ -111,6 +112,15 @@ contract Bug {
overshadowed.append( overshadowed.append(
(self.OVERSHADOWED_STATE_VARIABLE, scope_state_variable) (self.OVERSHADOWED_STATE_VARIABLE, scope_state_variable)
) )
# Check named return variables
for named_return in function.returns:
# Shadowed local delcarations in the same function will have "_scope_" in their name.
# See `FunctionSolc._add_local_variable`
if (
"_scope_" in variable.name
and variable.name.split("_scope_")[0] == named_return.name
):
overshadowed.append((self.OVERSHADOWED_RETURN_VARIABLE, named_return))
# If we have found any overshadowed objects, we'll want to add it to our result list. # If we have found any overshadowed objects, we'll want to add it to our result list.
if overshadowed: if overshadowed:

@ -7,7 +7,11 @@ from slither.core.cfg.node import Node
from slither.core.declarations import Function from slither.core.declarations import Function
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
)
from slither.utils.output import Output from slither.utils.output import Output
@ -54,6 +58,8 @@ Additionally, the for-loop uses the variable `max`, which is declared in a previ
WIKI_RECOMMENDATION = "Move all variable declarations prior to any usage of the variable, and ensure that reaching a variable declaration does not depend on some conditional if it is used unconditionally." WIKI_RECOMMENDATION = "Move all variable declarations prior to any usage of the variable, and ensure that reaching a variable declaration does not depend on some conditional if it is used unconditionally."
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def detect_predeclared_local_usage( def detect_predeclared_local_usage(
self, self,
node: Node, node: Node,

@ -103,9 +103,11 @@ Bob calls `func`. As a result, `owner` is overridden to `0`.
for contract in self.compilation_unit.contracts: for contract in self.compilation_unit.contracts:
for function in contract.functions: for function in contract.functions:
if function.is_implemented and function.entry_point: if function.is_implemented and function.entry_point:
locals_except_params = set(function.variables) - set(function.parameters)
uninitialized_storage_variables = [ uninitialized_storage_variables = [
v for v in function.local_variables if v.is_storage and v.uninitialized v for v in locals_except_params if v.is_storage and v.uninitialized
] ]
function.entry_point.context[self.key] = uninitialized_storage_variables function.entry_point.context[self.key] = uninitialized_storage_variables
self._detect_uninitialized(function, function.entry_point, []) self._detect_uninitialized(function, function.entry_point, [])

@ -12,6 +12,7 @@ from slither.core.declarations.solidity_variables import (
) )
from slither.core.expressions import NewContract from slither.core.expressions import NewContract
from slither.core.slither_core import SlitherCore from slither.core.slither_core import SlitherCore
from slither.core.solidity_types import TypeAlias
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.printers.abstract_printer import AbstractPrinter from slither.printers.abstract_printer import AbstractPrinter
@ -30,8 +31,8 @@ from slither.slithir.operations import (
) )
from slither.slithir.operations.binary import Binary from slither.slithir.operations.binary import Binary
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
from slither.visitors.expression.constants_folding import ConstantFolding
from slither.utils.output import Output from slither.utils.output import Output
from slither.visitors.expression.constants_folding import ConstantFolding
def _get_name(f: Union[Function, Variable]) -> str: def _get_name(f: Union[Function, Variable]) -> str:
@ -184,7 +185,11 @@ def _extract_constants_from_irs( # pylint: disable=too-many-branches,too-many-n
all_cst_used.append(ConstantValue(str(cst.value), str(type_))) all_cst_used.append(ConstantValue(str(cst.value), str(type_)))
if isinstance(ir, TypeConversion): if isinstance(ir, TypeConversion):
if isinstance(ir.variable, Constant): if isinstance(ir.variable, Constant):
all_cst_used.append(ConstantValue(str(ir.variable.value), str(ir.type))) if isinstance(ir.type, TypeAlias):
value_type = ir.type.type
else:
value_type = ir.type
all_cst_used.append(ConstantValue(str(ir.variable.value), str(value_type)))
continue continue
if ( if (
isinstance(ir, Member) isinstance(ir, Member)

@ -188,6 +188,16 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes
instance = detector_class(compilation_unit, self, logger_detector) instance = detector_class(compilation_unit, self, logger_detector)
self._detectors.append(instance) self._detectors.append(instance)
def unregister_detector(self, detector_class: Type[AbstractDetector]) -> None:
"""
:param detector_class: Class inheriting from `AbstractDetector`.
"""
for obj in self._detectors:
if isinstance(obj, detector_class):
self._detectors.remove(obj)
return
def register_printer(self, printer_class: Type[AbstractPrinter]) -> None: def register_printer(self, printer_class: Type[AbstractPrinter]) -> None:
""" """
:param printer_class: Class inheriting from `AbstractPrinter`. :param printer_class: Class inheriting from `AbstractPrinter`.
@ -197,6 +207,16 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes
instance = printer_class(self, logger_printer) instance = printer_class(self, logger_printer)
self._printers.append(instance) self._printers.append(instance)
def unregister_printer(self, printer_class: Type[AbstractPrinter]) -> None:
"""
:param printer_class: Class inheriting from `AbstractPrinter`.
"""
for obj in self._printers:
if isinstance(obj, printer_class):
self._printers.remove(obj)
return
def run_detectors(self) -> List[Dict]: def run_detectors(self) -> List[Dict]:
""" """
:return: List of registered detectors results. :return: List of registered detectors results.

@ -525,9 +525,7 @@ def _convert_type_contract(ir: Member) -> Assignment:
raise SlithIRError(f"type({contract.name}).{ir.variable_right} is unknown") raise SlithIRError(f"type({contract.name}).{ir.variable_right} is unknown")
def propagate_types( def propagate_types(ir: Operation, node: "Node"): # pylint: disable=too-many-locals
ir: slither.slithir.operations.operation.Operation, node: "Node"
): # pylint: disable=too-many-locals
# propagate the type # propagate the type
node_function = node.function node_function = node.function
using_for = ( using_for = (
@ -577,9 +575,9 @@ def propagate_types(
if (isinstance(t, ElementaryType) and t.name == "address") or ( if (isinstance(t, ElementaryType) and t.name == "address") or (
isinstance(t, TypeAlias) and t.underlying_type.name == "address" isinstance(t, TypeAlias) and t.underlying_type.name == "address"
): ):
# Cannot be a top level function with this.
assert isinstance(node_function, FunctionContract)
if ir.destination.name == "this": if ir.destination.name == "this":
# Cannot be a top level function with this.
assert isinstance(node_function, FunctionContract)
# the target contract is the contract itself # the target contract is the contract itself
return convert_type_of_high_and_internal_level_call( return convert_type_of_high_and_internal_level_call(
ir, node_function.contract ir, node_function.contract

@ -780,12 +780,35 @@ class ContractSolc(CallerContextExpression):
self._customErrorParsed = [] self._customErrorParsed = []
def _handle_comment(self, attributes: Dict) -> None: def _handle_comment(self, attributes: Dict) -> None:
"""
Save the contract comment in self.comments
And handle custom slither comments
Args:
attributes:
Returns:
"""
# Old solc versions store the comment in attributes["documentation"]
# More recent ones store it in attributes["documentation"]["text"]
if ( if (
"documentation" in attributes "documentation" in attributes
and attributes["documentation"] is not None and attributes["documentation"] is not None
and "text" in attributes["documentation"] and (
"text" in attributes["documentation"]
or isinstance(attributes["documentation"], str)
)
): ):
candidates = attributes["documentation"]["text"].replace("\n", ",").split(",") text = (
attributes["documentation"]
if isinstance(attributes["documentation"], str)
else attributes["documentation"]["text"]
)
self._contract.comments = text
# Look for custom comments
candidates = text.replace("\n", ",").split(",")
for candidate in candidates: for candidate in candidates:
if "@custom:security isDelegatecallProxy" in candidate: if "@custom:security isDelegatecallProxy" in candidate:

@ -49,7 +49,7 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few-
type_name = parse_type(self._type_name, self) type_name = parse_type(self._type_name, self)
self._using_for.using_for[type_name] = [] self._using_for.using_for[type_name] = []
if self._library_name is not None: if self._library_name:
library_name = parse_type(self._library_name, self) library_name = parse_type(self._library_name, self)
self._using_for.using_for[type_name].append(library_name) self._using_for.using_for[type_name].append(library_name)
self._propagate_global(type_name) self._propagate_global(type_name)
@ -90,8 +90,13 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few-
def _analyze_top_level_function( def _analyze_top_level_function(
self, function_name: str, type_name: Union[TypeAliasTopLevel, UserDefinedType] self, function_name: str, type_name: Union[TypeAliasTopLevel, UserDefinedType]
) -> None: ) -> None:
for tl_function in self.compilation_unit.functions_top_level: for tl_function in self._using_for.file_scope.functions:
if tl_function.name == function_name: # The library function is bound to the first parameter's type
if (
tl_function.name == function_name
and tl_function.parameters
and type_name == tl_function.parameters[0].type
):
self._using_for.using_for[type_name].append(tl_function) self._using_for.using_for[type_name].append(tl_function)
self._propagate_global(type_name) self._propagate_global(type_name)
break break
@ -108,7 +113,12 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few-
break break
if c.name == library_name: if c.name == library_name:
for cf in c.functions: for cf in c.functions:
if cf.name == function_name: # The library function is bound to the first parameter's type
if (
cf.name == function_name
and cf.parameters
and type_name == cf.parameters[0].type
):
self._using_for.using_for[type_name].append(cf) self._using_for.using_for[type_name].append(cf)
self._propagate_global(type_name) self._propagate_global(type_name)
found = True found = True

@ -169,7 +169,9 @@ def convert_result_to_markdown(txt: str) -> str:
return "".join(ret) return "".join(ret)
def output_results_to_markdown(all_results: List[Dict], checklistlimit: str) -> None: def output_results_to_markdown(
all_results: List[Dict], checklistlimit: str, show_ignored_findings: bool
) -> None:
checks = defaultdict(list) checks = defaultdict(list)
info: Dict = defaultdict(dict) info: Dict = defaultdict(dict)
for results_ in all_results: for results_ in all_results:
@ -179,6 +181,11 @@ def output_results_to_markdown(all_results: List[Dict], checklistlimit: str) ->
"confidence": results_["confidence"], "confidence": results_["confidence"],
} }
if not show_ignored_findings:
print(
"**THIS CHECKLIST IS NOT COMPLETE**. Use `--show-ignored-findings` to show all the results."
)
print("Summary") print("Summary")
for check_ in checks: for check_ in checks:
print( print(

@ -1,7 +1,13 @@
import math import math
from typing import List, Union, Set from typing import List, Union, Set
from slither.core.solidity_types import ArrayType, MappingType, ElementaryType, UserDefinedType from slither.core.solidity_types import (
ArrayType,
MappingType,
ElementaryType,
UserDefinedType,
TypeAlias,
)
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
@ -89,6 +95,9 @@ def convert_type_for_solidity_signature(t: Type, seen: Set[Type]) -> Union[Type,
] ]
return types return types
if isinstance(t, TypeAlias):
return t.type
return t return t

@ -0,0 +1,7 @@
/**
* @title Test Contract
* @dev Test comment
*/
contract A{
}

@ -24,3 +24,13 @@ contract FurtherExtendedContract is ExtendedContract {
function shadowingParent(uint x) public pure { int y; uint z; uint w; uint v; } function shadowingParent(uint x) public pure { int y; uint z; uint w; uint v; }
} }
contract LocalReturnVariables {
uint state;
function shadowedState() external view returns(uint state) {
return state;
}
function good() external view returns(uint val1) {
return val1;
}
}

@ -204,6 +204,129 @@
"impact": "Low", "impact": "Low",
"confidence": "High" "confidence": "High"
}, },
{
"elements": [
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 533,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30
],
"starting_column": 52,
"ending_column": 62
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedState",
"source_mapping": {
"start": 486,
"length": 88,
"filename_relative": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30,
31,
32
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 434,
"length": 225,
"filename_relative": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedState()"
}
}
}
},
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 470,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
29
],
"starting_column": 5,
"ending_column": 15
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 434,
"length": 225,
"filename_relative": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37
],
"starting_column": 1,
"ending_column": 0
}
}
}
}
],
"description": "LocalReturnVariables.shadowedState().state (tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol#30) shadows:\n\t- LocalReturnVariables.state (tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol#29) (state variable)\n",
"markdown": "[LocalReturnVariables.shadowedState().state](tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol#L30) shadows:\n\t- [LocalReturnVariables.state](tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol#L29) (state variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.4.25/shadowing_local_variable.sol#L30",
"id": "1b0030affabcff703e57e4f388b86dbda0f412e51ba8d15248bcae9e4748a012",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {

@ -24,3 +24,17 @@ contract FurtherExtendedContract is ExtendedContract {
function shadowingParent(uint x) public pure { int y; uint z; uint w; uint v; } function shadowingParent(uint x) public pure { int y; uint z; uint w; uint v; }
} }
contract LocalReturnVariables {
uint state;
function shadowedState() external view returns(uint state) {
return state;
}
function shadowedReturn() external view returns(uint local) {
uint local = 1;
return local;
}
function good() external view returns(uint val1) {
return val1;
}
}

@ -204,6 +204,137 @@
"impact": "Low", "impact": "Low",
"confidence": "High" "confidence": "High"
}, },
{
"elements": [
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 536,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30
],
"starting_column": 52,
"ending_column": 62
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedState",
"source_mapping": {
"start": 489,
"length": 88,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30,
31,
32
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 437,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedState()"
}
}
}
},
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 473,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
29
],
"starting_column": 5,
"ending_column": 15
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 437,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
}
}
}
],
"description": "LocalReturnVariables.shadowedState().state (tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#30) shadows:\n\t- LocalReturnVariables.state (tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#29) (state variable)\n",
"markdown": "[LocalReturnVariables.shadowedState().state](tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#L30) shadows:\n\t- [LocalReturnVariables.state](tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#L29) (state variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#L30",
"id": "1b0030affabcff703e57e4f388b86dbda0f412e51ba8d15248bcae9e4748a012",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {
@ -567,6 +698,161 @@
"impact": "Low", "impact": "Low",
"confidence": "High" "confidence": "High"
}, },
{
"elements": [
{
"type": "variable",
"name": "local_scope_0",
"source_mapping": {
"start": 653,
"length": 14,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
34
],
"starting_column": 9,
"ending_column": 23
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedReturn",
"source_mapping": {
"start": 583,
"length": 113,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33,
34,
35,
36
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 437,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedReturn()"
}
}
}
},
{
"type": "variable",
"name": "local",
"source_mapping": {
"start": 631,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33
],
"starting_column": 53,
"ending_column": 63
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedReturn",
"source_mapping": {
"start": 583,
"length": 113,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33,
34,
35,
36
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 437,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedReturn()"
}
}
}
}
],
"description": "LocalReturnVariables.shadowedReturn().local_scope_0 (tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#34) shadows:\n\t- LocalReturnVariables.shadowedReturn().local (tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#33) (return variable)\n",
"markdown": "[LocalReturnVariables.shadowedReturn().local_scope_0](tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#L34) shadows:\n\t- [LocalReturnVariables.shadowedReturn().local](tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#L33) (return variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.5.16/shadowing_local_variable.sol#L34",
"id": "cd63bdf3f6420e4e109d20ec44b52fcbcbde1c5b6a0701fc6994b35960ab1e85",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {

@ -24,3 +24,17 @@ contract FurtherExtendedContract is ExtendedContract {
function shadowingParent(uint __x) public pure { int y; uint z; uint w; uint v; } function shadowingParent(uint __x) public pure { int y; uint z; uint w; uint v; }
} }
contract LocalReturnVariables {
uint state;
function shadowedState() external view returns(uint state) {
return state;
}
function shadowedReturn() external view returns(uint local) {
uint local = 1;
return local;
}
function good() external view returns(uint val1) {
return val1;
}
}

@ -1,5 +1,136 @@
[ [
[ [
{
"elements": [
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 541,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30
],
"starting_column": 52,
"ending_column": 62
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedState",
"source_mapping": {
"start": 494,
"length": 88,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30,
31,
32
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedState()"
}
}
}
},
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 478,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
29
],
"starting_column": 5,
"ending_column": 15
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
}
}
}
],
"description": "LocalReturnVariables.shadowedState().state (tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#30) shadows:\n\t- LocalReturnVariables.state (tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#29) (state variable)\n",
"markdown": "[LocalReturnVariables.shadowedState().state](tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#L30) shadows:\n\t- [LocalReturnVariables.state](tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#L29) (state variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#L30",
"id": "1b0030affabcff703e57e4f388b86dbda0f412e51ba8d15248bcae9e4748a012",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {
@ -486,6 +617,161 @@
"impact": "Low", "impact": "Low",
"confidence": "High" "confidence": "High"
}, },
{
"elements": [
{
"type": "variable",
"name": "local_scope_0",
"source_mapping": {
"start": 658,
"length": 14,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
34
],
"starting_column": 9,
"ending_column": 23
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedReturn",
"source_mapping": {
"start": 588,
"length": 113,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33,
34,
35,
36
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedReturn()"
}
}
}
},
{
"type": "variable",
"name": "local",
"source_mapping": {
"start": 636,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33
],
"starting_column": 53,
"ending_column": 63
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedReturn",
"source_mapping": {
"start": 588,
"length": 113,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33,
34,
35,
36
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 0
}
},
"signature": "shadowedReturn()"
}
}
}
}
],
"description": "LocalReturnVariables.shadowedReturn().local_scope_0 (tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#34) shadows:\n\t- LocalReturnVariables.shadowedReturn().local (tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#33) (return variable)\n",
"markdown": "[LocalReturnVariables.shadowedReturn().local_scope_0](tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#L34) shadows:\n\t- [LocalReturnVariables.shadowedReturn().local](tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#L33) (return variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.6.11/shadowing_local_variable.sol#L34",
"id": "cd63bdf3f6420e4e109d20ec44b52fcbcbde1c5b6a0701fc6994b35960ab1e85",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {

@ -24,3 +24,17 @@ contract FurtherExtendedContract is ExtendedContract {
function shadowingParent(uint __x) public pure { int y; uint z; uint w; uint v; } function shadowingParent(uint __x) public pure { int y; uint z; uint w; uint v; }
} }
contract LocalReturnVariables {
uint state;
function shadowedState() external view returns(uint state) {
return state;
}
function shadowedReturn() external view returns(uint local) {
uint local = 1;
return local;
}
function good() external view returns(uint val1) {
return val1;
}
}

@ -1,5 +1,134 @@
[ [
[ [
{
"elements": [
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 541,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30
],
"starting_column": 52,
"ending_column": 62
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedState",
"source_mapping": {
"start": 494,
"length": 88,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
30,
31,
32
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "shadowedState()"
}
}
}
},
{
"type": "variable",
"name": "state",
"source_mapping": {
"start": 478,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
29
],
"starting_column": 5,
"ending_column": 15
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
],
"description": "LocalReturnVariables.shadowedState().state (tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#30) shadows:\n\t- LocalReturnVariables.state (tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#29) (state variable)\n",
"markdown": "[LocalReturnVariables.shadowedState().state](tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#L30) shadows:\n\t- [LocalReturnVariables.state](tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#L29) (state variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#L30",
"id": "1b0030affabcff703e57e4f388b86dbda0f412e51ba8d15248bcae9e4748a012",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {
@ -486,6 +615,159 @@
"impact": "Low", "impact": "Low",
"confidence": "High" "confidence": "High"
}, },
{
"elements": [
{
"type": "variable",
"name": "local_scope_0",
"source_mapping": {
"start": 658,
"length": 14,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
34
],
"starting_column": 9,
"ending_column": 23
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedReturn",
"source_mapping": {
"start": 588,
"length": 113,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33,
34,
35,
36
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "shadowedReturn()"
}
}
}
},
{
"type": "variable",
"name": "local",
"source_mapping": {
"start": 636,
"length": 10,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33
],
"starting_column": 53,
"ending_column": 63
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "shadowedReturn",
"source_mapping": {
"start": 588,
"length": 113,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
33,
34,
35,
36
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "LocalReturnVariables",
"source_mapping": {
"start": 442,
"length": 344,
"filename_relative": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol",
"is_dependency": false,
"lines": [
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "shadowedReturn()"
}
}
}
}
],
"description": "LocalReturnVariables.shadowedReturn().local_scope_0 (tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#34) shadows:\n\t- LocalReturnVariables.shadowedReturn().local (tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#33) (return variable)\n",
"markdown": "[LocalReturnVariables.shadowedReturn().local_scope_0](tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#L34) shadows:\n\t- [LocalReturnVariables.shadowedReturn().local](tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#L33) (return variable)\n",
"first_markdown_element": "tests/detectors/shadowing-local/0.7.6/shadowing_local_variable.sol#L34",
"id": "cd63bdf3f6420e4e109d20ec44b52fcbcbde1c5b6a0701fc6994b35960ab1e85",
"check": "shadowing-local",
"impact": "Low",
"confidence": "High"
},
{ {
"elements": [ "elements": [
{ {

@ -0,0 +1,17 @@
contract Uninitialized{
struct St{
uint a;
}
function bad() internal returns (St storage ret){
ret = ret;
ret.a += 1;
}
function ok(St storage ret) internal {
ret = ret;
ret.a += 1;
}
}

@ -0,0 +1,90 @@
[
[
{
"elements": [
{
"type": "variable",
"name": "ret",
"source_mapping": {
"start": 100,
"length": 14,
"filename_relative": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol",
"is_dependency": false,
"lines": [
7
],
"starting_column": 38,
"ending_column": 52
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "bad",
"source_mapping": {
"start": 67,
"length": 95,
"filename_relative": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol",
"is_dependency": false,
"lines": [
7,
8,
9,
10
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Uninitialized",
"source_mapping": {
"start": 0,
"length": 262,
"filename_relative": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol",
"is_dependency": false,
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "bad()"
}
}
}
}
],
"description": "Uninitialized.bad().ret (tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol#7) is a storage variable never initialized\n",
"markdown": "[Uninitialized.bad().ret](tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol#L7) is a storage variable never initialized\n",
"first_markdown_element": "tests/detectors/uninitialized-storage/0.8.19/uninitialized_storage_pointer.sol#L7",
"id": "979d28e501693ed7ece0d429e7c30266f8e9d6a2e2eedc87006c4bad63e78706",
"check": "uninitialized-storage",
"impact": "High",
"confidence": "High"
}
]
]

@ -371,6 +371,11 @@ ALL_TEST_OBJECTS = [
"uninitialized_storage_pointer.sol", "uninitialized_storage_pointer.sol",
"0.4.25", "0.4.25",
), ),
Test(
all_detectors.UninitializedStorageVars,
"uninitialized_storage_pointer.sol",
"0.8.19",
),
Test(all_detectors.TxOrigin, "tx_origin.sol", "0.4.25"), Test(all_detectors.TxOrigin, "tx_origin.sol", "0.4.25"),
Test(all_detectors.TxOrigin, "tx_origin.sol", "0.5.16"), Test(all_detectors.TxOrigin, "tx_origin.sol", "0.5.16"),
Test(all_detectors.TxOrigin, "tx_origin.sol", "0.6.11"), Test(all_detectors.TxOrigin, "tx_origin.sol", "0.6.11"),

@ -1,4 +1,5 @@
import inspect import inspect
from pathlib import Path
from crytic_compile import CryticCompile from crytic_compile import CryticCompile
from crytic_compile.platform.solc_standard_json import SolcStandardJson from crytic_compile.platform.solc_standard_json import SolcStandardJson
@ -8,7 +9,7 @@ from slither import Slither
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.detectors import all_detectors from slither.detectors import all_detectors
from slither.detectors.abstract_detector import AbstractDetector from slither.detectors.abstract_detector import AbstractDetector
from slither.slithir.operations import LibraryCall, InternalCall from slither.slithir.operations import InternalCall, LibraryCall
from slither.utils.arithmetic import unchecked_arithemtic_usage from slither.utils.arithmetic import unchecked_arithemtic_usage
@ -31,7 +32,7 @@ def test_node() -> None:
def test_collision() -> None: def test_collision() -> None:
solc_select.switch_global_version("0.8.0", always_install=True)
standard_json = SolcStandardJson() standard_json = SolcStandardJson()
standard_json.add_source_file("./tests/collisions/a.sol") standard_json.add_source_file("./tests/collisions/a.sol")
standard_json.add_source_file("./tests/collisions/b.sol") standard_json.add_source_file("./tests/collisions/b.sol")
@ -43,6 +44,7 @@ def test_collision() -> None:
def test_cycle() -> None: def test_cycle() -> None:
solc_select.switch_global_version("0.8.0", always_install=True)
slither = Slither("./tests/test_cyclic_import/a.sol") slither = Slither("./tests/test_cyclic_import/a.sol")
_run_all_detectors(slither) _run_all_detectors(slither)
@ -74,6 +76,36 @@ def test_upgradeable_comments() -> None:
assert v1.upgradeable_version == "version_1" assert v1.upgradeable_version == "version_1"
def test_contract_comments() -> None:
comments = " @title Test Contract\n @dev Test comment"
solc_select.switch_global_version("0.8.10", always_install=True)
slither = Slither("./tests/custom_comments/contract_comment.sol")
compilation_unit = slither.compilation_units[0]
contract = compilation_unit.get_contract_from_name("A")[0]
assert contract.comments == comments
# Old solc versions have a different parsing of comments
# the initial space (after *) is also not kept on every line
comments = "@title Test Contract\n@dev Test comment"
solc_select.switch_global_version("0.5.16", always_install=True)
slither = Slither("./tests/custom_comments/contract_comment.sol")
compilation_unit = slither.compilation_units[0]
contract = compilation_unit.get_contract_from_name("A")[0]
assert contract.comments == comments
# Test with legacy AST
comments = "@title Test Contract\n@dev Test comment"
solc_select.switch_global_version("0.5.16", always_install=True)
slither = Slither("./tests/custom_comments/contract_comment.sol", solc_force_legacy_json=True)
compilation_unit = slither.compilation_units[0]
contract = compilation_unit.get_contract_from_name("A")[0]
assert contract.comments == comments
def test_using_for_top_level_same_name() -> None: def test_using_for_top_level_same_name() -> None:
solc_select.switch_global_version("0.8.15", always_install=True) solc_select.switch_global_version("0.8.15", always_install=True)
slither = Slither("./tests/ast-parsing/using-for-3-0.8.0.sol") slither = Slither("./tests/ast-parsing/using-for-3-0.8.0.sol")
@ -160,3 +192,13 @@ def test_arithmetic_usage() -> None:
assert { assert {
f.source_mapping.content_hash for f in unchecked_arithemtic_usage(slither.contracts[0]) f.source_mapping.content_hash for f in unchecked_arithemtic_usage(slither.contracts[0])
} == {"2b4bc73cf59d486dd9043e840b5028b679354dd9", "e4ecd4d0fda7e762d29aceb8425f2c5d4d0bf962"} } == {"2b4bc73cf59d486dd9043e840b5028b679354dd9", "e4ecd4d0fda7e762d29aceb8425f2c5d4d0bf962"}
def test_using_for_global_collision() -> None:
solc_select.switch_global_version("0.8.18", always_install=True)
standard_json = SolcStandardJson()
for source_file in Path("./tests/using-for-global-collision").rglob("*.sol"):
standard_json.add_source_file(Path(source_file).as_posix())
compilation = CryticCompile(standard_json)
sl = Slither(compilation)
_run_all_detectors(sl)

@ -0,0 +1,2 @@
import "./MyTypeA/Type.sol";
import "./MyTypeA/Math.sol";

@ -0,0 +1,4 @@
import "./Type.sol";
function unwrap(MyTypeA a) pure returns (int256) {
return MyTypeA.unwrap(a);
}

@ -0,0 +1,5 @@
import "./Type.sol";
function mul(MyTypeA a, MyTypeA b) pure returns (MyTypeA) {
return MyTypeA.wrap(MyTypeA.unwrap(a) * MyTypeA.unwrap(b));
}

@ -0,0 +1,6 @@
import "./Casting.sol" as C;
import "./Math.sol" as M;
type MyTypeA is int256;
using {M.mul, C.unwrap} for MyTypeA global;

@ -0,0 +1,2 @@
import "./MyTypeB/Type.sol";
import "./MyTypeB/Math.sol";

@ -0,0 +1,4 @@
import "./Type.sol";
function unwrap(MyTypeB a) pure returns (uint256) {
return MyTypeB.unwrap(a);
}

@ -0,0 +1,6 @@
import "./Type.sol";
function mul(MyTypeB a, MyTypeB b) pure returns (MyTypeB) {
return MyTypeB.wrap(MyTypeB.unwrap(a) * MyTypeB.unwrap(b));
}

@ -0,0 +1,6 @@
import "./Casting.sol" as C;
import "./Math.sol" as M;
type MyTypeB is uint256;
using {M.mul, C.unwrap} for MyTypeB global;

@ -0,0 +1,7 @@
import "./MyTypeB.sol";
contract UsingForGlobalTopLevelCollision {
function mulAndUnwrap(MyTypeB x, MyTypeB y) external pure returns (uint256 z) {
z = x.mul(y).unwrap();
}
}
Loading…
Cancel
Save