Improve constant folding (Fix #820)

pull/830/head
Josselin 4 years ago
parent a988d9c89e
commit e2fd9d2c19
  1. 27
      slither/slithir/variables/constant.py
  2. 25
      slither/utils/integer_conversion.py
  3. 3
      slither/visitors/expression/constants_folding.py

@ -1,10 +1,10 @@
from functools import total_ordering
from decimal import Decimal from decimal import Decimal
from functools import total_ordering
from slither.slithir.variables.variable import SlithIRVariable
from slither.slithir.exceptions import SlithIRError
from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint
from slither.slithir.variables.variable import SlithIRVariable
from slither.utils.arithmetic import convert_subdenomination from slither.utils.arithmetic import convert_subdenomination
from slither.utils.integer_conversion import convert_string_to_int
@total_ordering @total_ordering
@ -25,26 +25,7 @@ class Constant(SlithIRVariable):
assert isinstance(constant_type, ElementaryType) assert isinstance(constant_type, ElementaryType)
self._type = constant_type self._type = constant_type
if constant_type.type in Int + Uint + ["address"]: if constant_type.type in Int + Uint + ["address"]:
if val.startswith("0x") or val.startswith("0X"): self._val = convert_string_to_int(val)
self._val = int(val, 16)
else:
if "e" in val or "E" in val:
base, expo = val.split("e") if "e" in val else val.split("E")
base, expo = Decimal(base), int(expo)
# The resulting number must be < 2**256-1, otherwise solc
# Would not be able to compile it
# 10**77 is the largest exponent that fits
# See https://github.com/ethereum/solidity/blob/9e61f92bd4d19b430cb8cb26f1c7cf79f1dff380/libsolidity/ast/Types.cpp#L1281-L1290
if expo > 77:
if base != Decimal(0):
raise SlithIRError(
f"{base}e{expo} is too large to fit in any Solidity integer size"
)
self._val = 0
else:
self._val = int(Decimal(base) * Decimal(10 ** expo))
else:
self._val = int(Decimal(val))
elif constant_type.type == "bool": elif constant_type.type == "bool":
self._val = (val == "true") | (val == "True") self._val = (val == "true") | (val == "True")
else: else:

@ -0,0 +1,25 @@
from decimal import Decimal
from slither.exceptions import SlitherError
def convert_string_to_int(val: str) -> int:
if val.startswith("0x") or val.startswith("0X"):
return int(val, 16)
if "e" in val or "E" in val:
base, expo = val.split("e") if "e" in val else val.split("E")
base, expo = Decimal(base), int(expo)
# The resulting number must be < 2**256-1, otherwise solc
# Would not be able to compile it
# 10**77 is the largest exponent that fits
# See https://github.com/ethereum/solidity/blob/9e61f92bd4d19b430cb8cb26f1c7cf79f1dff380/libsolidity/ast/Types.cpp#L1281-L1290
if expo > 77:
if base != Decimal(0):
raise SlitherError(
f"{base}e{expo} is too large to fit in any Solidity integer size"
)
return 0
return int(Decimal(base) * Decimal(10 ** expo))
return int(Decimal(val))

@ -1,4 +1,5 @@
from slither.core.expressions import BinaryOperationType, Literal from slither.core.expressions import BinaryOperationType, Literal
from slither.utils.integer_conversion import convert_string_to_int
from slither.visitors.expression.expression import ExpressionVisitor from slither.visitors.expression.expression import ExpressionVisitor
@ -36,7 +37,7 @@ class ConstantFolding(ExpressionVisitor):
if not isinstance(expr, Literal): if not isinstance(expr, Literal):
cf = ConstantFolding(expr, self._type) cf = ConstantFolding(expr, self._type)
expr = cf.result() expr = cf.result()
set_val(expression, int(expr.value)) set_val(expression, convert_string_to_int(expr.value))
def _post_binary_operation(self, expression): def _post_binary_operation(self, expression):
left = get_val(expression.expression_left) left = get_val(expression.expression_left)

Loading…
Cancel
Save