Unify parsing of integers with convert_string_to_int/fraction

pull/1377/head
Emilio López 2 years ago
parent 036f7d62f4
commit ce801942ab
  1. 3
      slither/slithir/variables/constant.py
  2. 29
      slither/utils/arithmetic.py
  3. 16
      slither/utils/integer_conversion.py
  4. 9
      slither/visitors/expression/constants_folding.py

@ -1,4 +1,3 @@
from fractions import Fraction
from functools import total_ordering from functools import total_ordering
from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint
@ -33,7 +32,7 @@ class Constant(SlithIRVariable):
else: else:
if val.isdigit(): if val.isdigit():
self._type = ElementaryType("uint256") self._type = ElementaryType("uint256")
self._val = int(Fraction(val)) self._val = convert_string_to_int(val)
else: else:
self._type = ElementaryType("string") self._type = ElementaryType("string")
self._val = val self._val = val

@ -1,38 +1,35 @@
from fractions import Fraction from fractions import Fraction
from slither.exceptions import SlitherException from slither.exceptions import SlitherException
from slither.utils.integer_conversion import convert_string_to_int
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
def convert_subdenomination( def convert_subdenomination(
value: str, sub: str value: str, sub: str
) -> int: # pylint: disable=too-many-return-statements ) -> int: # pylint: disable=too-many-return-statements
# to allow 0.1 ether conversion decimal_value = convert_string_to_int(value)
if value[0:2] == "0x":
decimal_value = Fraction(int(value, 16))
else:
decimal_value = Fraction(value)
if sub == "wei": if sub == "wei":
return int(decimal_value) return decimal_value
if sub == "gwei": if sub == "gwei":
return int(decimal_value * int(1e9)) return decimal_value * 1e9
if sub == "szabo": if sub == "szabo":
return int(decimal_value * int(1e12)) return decimal_value * 1e12
if sub == "finney": if sub == "finney":
return int(decimal_value * int(1e15)) return decimal_value * 1e15
if sub == "ether": if sub == "ether":
return int(decimal_value * int(1e18)) return decimal_value * 1e18
if sub == "seconds": if sub == "seconds":
return int(decimal_value) return decimal_value
if sub == "minutes": if sub == "minutes":
return int(decimal_value * 60) return decimal_value * 60
if sub == "hours": if sub == "hours":
return int(decimal_value * 60 * 60) return decimal_value * 60 * 60
if sub == "days": if sub == "days":
return int(decimal_value * 60 * 60 * 24) return decimal_value * 60 * 60 * 24
if sub == "weeks": if sub == "weeks":
return int(decimal_value * 60 * 60 * 24 * 7) return decimal_value * 60 * 60 * 24 * 7
if sub == "years": if sub == "years":
return int(decimal_value * 60 * 60 * 24 * 7 * 365) return decimal_value * 60 * 60 * 24 * 7 * 365
raise SlitherException(f"Subdemonination conversion impossible {decimal_value} {sub}") raise SlitherException(f"Subdemonination conversion impossible {decimal_value} {sub}")

@ -4,11 +4,14 @@ from typing import Union
from slither.exceptions import SlitherError from slither.exceptions import SlitherError
def convert_string_to_int(val: Union[str, int]) -> int: def convert_string_to_fraction(val: Union[str, int]) -> Fraction:
if isinstance(val, int): if isinstance(val, int):
return val return Fraction(val)
if val.startswith(("0x", "0X")): if val.startswith(("0x", "0X")):
return int(val, 16) return Fraction(int(val, 16))
# Fractions do not support underscore separators (on Python <3.11)
val = val.replace('_', '')
if "e" in val or "E" in val: if "e" in val or "E" in val:
base, expo = val.split("e") if "e" in val else val.split("E") base, expo = val.split("e") if "e" in val else val.split("E")
@ -23,6 +26,9 @@ def convert_string_to_int(val: Union[str, int]) -> int:
f"{base}e{expo} is too large to fit in any Solidity integer size" f"{base}e{expo} is too large to fit in any Solidity integer size"
) )
return 0 return 0
return int(Fraction(base) * Fraction(10**expo)) return Fraction(base) * Fraction(10**expo)
return int(Fraction(val)) return Fraction(val)
def convert_string_to_int(val: Union[str, int]) -> int:
return int(convert_string_to_fraction(val))

@ -1,6 +1,5 @@
from fractions import Fraction
from slither.core.expressions import BinaryOperationType, Literal, UnaryOperationType from slither.core.expressions import BinaryOperationType, Literal, UnaryOperationType
from slither.utils.integer_conversion import convert_string_to_int from slither.utils.integer_conversion import convert_string_to_fraction, convert_string_to_int
from slither.visitors.expression.expression import ExpressionVisitor from slither.visitors.expression.expression import ExpressionVisitor
@ -73,13 +72,13 @@ class ConstantFolding(ExpressionVisitor):
cf = ConstantFolding(expr, self._type) cf = ConstantFolding(expr, self._type)
expr = cf.result() expr = cf.result()
assert isinstance(expr, Literal) assert isinstance(expr, Literal)
set_val(expression, int(expr.value)) set_val(expression, -convert_string_to_fraction(expr.value))
else: else:
raise NotConstant raise NotConstant
def _post_literal(self, expression): def _post_literal(self, expression):
try: try:
set_val(expression, Fraction(expression.value)) set_val(expression, convert_string_to_fraction(expression.value))
except ValueError: except ValueError:
raise NotConstant raise NotConstant
@ -116,7 +115,7 @@ class ConstantFolding(ExpressionVisitor):
cf = ConstantFolding(expression.expressions[0], self._type) cf = ConstantFolding(expression.expressions[0], self._type)
expr = cf.result() expr = cf.result()
assert isinstance(expr, Literal) assert isinstance(expr, Literal)
set_val(expression, int(expr.value)) set_val(expression, convert_string_to_fraction(expr.value))
return return
raise NotConstant raise NotConstant

Loading…
Cancel
Save