Merge branch 'dev' into fix-web3

pull/2537/head
alpharush 2 months ago committed by GitHub
commit 610c30174a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/publish.yml
  2. 2
      setup.py
  3. 4
      slither/printers/summary/loc.py
  4. 39
      slither/tools/mutator/mutators/AOR.py
  5. 4
      slither/utils/command_line.py
  6. 26
      slither/utils/myprettytable.py

@ -47,7 +47,7 @@ jobs:
uses: pypa/gh-action-pypi-publish@v1.9.0 uses: pypa/gh-action-pypi-publish@v1.9.0
- name: sign - name: sign
uses: sigstore/gh-action-sigstore-python@v2.1.1 uses: sigstore/gh-action-sigstore-python@v3.0.0
with: with:
inputs: ./dist/*.tar.gz ./dist/*.whl inputs: ./dist/*.tar.gz ./dist/*.whl
release-signing-artifacts: true release-signing-artifacts: true

@ -13,7 +13,7 @@ setup(
python_requires=">=3.8", python_requires=">=3.8",
install_requires=[ install_requires=[
"packaging", "packaging",
"prettytable>=3.3.0", "prettytable>=3.10.2",
"pycryptodome>=3.4.6", "pycryptodome>=3.4.6",
"crytic-compile>=0.3.7,<0.4.0", "crytic-compile>=0.3.7,<0.4.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",

@ -17,8 +17,8 @@ from slither.utils.output import Output
class LocPrinter(AbstractPrinter): class LocPrinter(AbstractPrinter):
ARGUMENT = "loc" ARGUMENT = "loc"
HELP = """Count the total number lines of code (LOC), source lines of code (SLOC), \ HELP = """Count the total number lines of code (LOC), source lines of code (SLOC),
and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), \ and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP),
and test files (TEST).""" and test files (TEST)."""
WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#loc" WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#loc"

@ -2,7 +2,12 @@ from typing import Dict
from slither.slithir.operations import Binary, BinaryType from slither.slithir.operations import Binary, BinaryType
from slither.tools.mutator.utils.patch import create_patch_with_line from slither.tools.mutator.utils.patch import create_patch_with_line
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator
from slither.core.variables.variable import Variable
from slither.core.expressions.unary_operation import UnaryOperation from slither.core.expressions.unary_operation import UnaryOperation
from slither.core.expressions.call_expression import CallExpression
from slither.core.expressions.member_access import MemberAccess
from slither.core.expressions.identifier import Identifier
from slither.core.solidity_types.array_type import ArrayType
arithmetic_operators = [ arithmetic_operators = [
BinaryType.ADDITION, BinaryType.ADDITION,
@ -27,7 +32,39 @@ class AOR(AbstractMutator): # pylint: disable=too-few-public-methods
ir_expression = node.expression ir_expression = node.expression
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
continue continue
for ir in node.irs:
# Special cases handling .push and .pop on dynamic arrays.
# The IR for these operations has a binary operation due to internal conversion
# (see convert_to_push and convert_to_pop in slithir/convert.py)
# however it's not present in the source code and should not be mutated.
# pylint: disable=too-many-boolean-expressions
if (
isinstance(ir_expression, CallExpression)
and isinstance(ir_expression.called, MemberAccess)
and ir_expression.called.member_name == "pop"
and isinstance(ir_expression.called.expression, Identifier)
and isinstance(ir_expression.called.expression.value, Variable)
and isinstance(ir_expression.called.expression.value.type, ArrayType)
):
continue
# For a .push instruction we skip the last 6 IR operations
# because they are fixed based on the internal conversion to the IR
# while we need to look at the preceding instructions because
# they might contain Binary IR to be mutated.
# For example for a.push(3+x) it's correct to mutate 3+x.
irs = (
node.irs[:-6]
if isinstance(ir_expression, CallExpression)
and isinstance(ir_expression.called, MemberAccess)
and ir_expression.called.member_name == "push"
and isinstance(ir_expression.called.expression, Identifier)
and isinstance(ir_expression.called.expression.value, Variable)
and isinstance(ir_expression.called.expression.value.type, ArrayType)
else node.irs
)
for ir in irs:
if isinstance(ir, Binary) and ir.type in arithmetic_operators: if isinstance(ir, Binary) and ir.type in arithmetic_operators:
if isinstance(ir_expression, UnaryOperation): if isinstance(ir_expression, UnaryOperation):
continue continue

@ -360,8 +360,10 @@ def output_printers(printer_classes: List[Type[AbstractPrinter]]) -> None:
printers_list = sorted(printers_list, key=lambda element: (element[0])) printers_list = sorted(printers_list, key=lambda element: (element[0]))
idx = 1 idx = 1
for (argument, help_info) in printers_list: for (argument, help_info) in printers_list:
table.add_row([str(idx), argument, help_info]) # Clean multi line HELP info
table.add_row([str(idx), argument, " ".join(x.strip() for x in help_info.splitlines())])
idx = idx + 1 idx = idx + 1
print(table) print(table)

@ -1,3 +1,4 @@
from shutil import get_terminal_size
from typing import List, Dict, Union from typing import List, Dict, Union
from prettytable import PrettyTable from prettytable import PrettyTable
@ -7,7 +8,12 @@ from slither.utils.colors import Colors
class MyPrettyTable: class MyPrettyTable:
def __init__(self, field_names: List[str], pretty_align: bool = True): # TODO: True by default? def __init__(
self,
field_names: List[str],
pretty_align: bool = True,
max_width: Union[int, None] = "max", # Default value is "max"
):
self._field_names = field_names self._field_names = field_names
self._rows: List = [] self._rows: List = []
self._options: Dict = {} self._options: Dict = {}
@ -19,6 +25,17 @@ class MyPrettyTable:
else: else:
self._options["set_alignment"] = [] self._options["set_alignment"] = []
self.max_width = None
if max_width == "max":
# We use (0,0) as a fallback to detect if we are not attached to a terminal
# In this case, we fall back to the default behavior (i.e. printing as much as possible)
terminal_column = get_terminal_size((0, 0)).columns
if terminal_column != 0:
# We reduce slightly the max-width to take into account inconsistencies in terminals
self.max_width = terminal_column - 3
else:
self.max_width = max_width
def add_row(self, row: List[Union[str, List[str]]]) -> None: def add_row(self, row: List[Union[str, List[str]]]) -> None:
self._rows.append(row) self._rows.append(row)
@ -28,6 +45,9 @@ class MyPrettyTable:
else: else:
table = PrettyTable(self._field_names) table = PrettyTable(self._field_names)
if self.max_width is not None:
table.max_table_width = self.max_width
for row in self._rows: for row in self._rows:
table.add_row(row) table.add_row(row)
if len(self._options["set_alignment"]): if len(self._options["set_alignment"]):
@ -63,7 +83,5 @@ def make_pretty_table(
table_row = [row] + [body[row][key] for key in headers[1:]] table_row = [row] + [body[row][key] for key in headers[1:]]
table.add_row(table_row) table.add_row(table_row)
if totals: if totals:
table.add_row( table.add_row([total_header] + [sum(body[row][key] for row in body) for key in headers[1:]])
[total_header] + [sum([body[row][key] for row in body]) for key in headers[1:]]
)
return table return table

Loading…
Cancel
Save