Merge pull request #241 from crytic/dev-support-type-contract

Add support for type(X) operation (creationCode, runtimeCode, name)
pull/242/head
Feist Josselin 6 years ago committed by GitHub
commit 7c7061a86c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      slither/core/declarations/solidity_variables.py
  2. 1
      slither/core/solidity_types/__init__.py
  3. 23
      slither/core/solidity_types/type_information.py
  4. 44
      slither/slithir/convert.py

@ -1,6 +1,6 @@
# https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html # https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html
from slither.core.context.context import Context from slither.core.context.context import Context
from slither.core.solidity_types import ElementaryType from slither.core.solidity_types import ElementaryType, TypeInformation
SOLIDITY_VARIABLES = {"now":'uint256', SOLIDITY_VARIABLES = {"now":'uint256',
"this":'address', "this":'address',
@ -57,7 +57,8 @@ SOLIDITY_FUNCTIONS = {"gasleft()":['uint256'],
"abi.encodeWithSelector()":["bytes"], "abi.encodeWithSelector()":["bytes"],
"abi.encodeWithSignature()":["bytes"], "abi.encodeWithSignature()":["bytes"],
# abi.decode returns an a list arbitrary types # abi.decode returns an a list arbitrary types
"abi.decode()":[]} "abi.decode()":[],
"type(address)":[]}
def solidity_function_signature(name): def solidity_function_signature(name):
""" """
@ -125,10 +126,15 @@ class SolidityVariableComposed(SolidityVariable):
class SolidityFunction: class SolidityFunction:
# Non standard handling of type(address). This function returns an undefined object
# The type is dynamic
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
# As a result, we set return_type during the Ir conversion
def __init__(self, name): def __init__(self, name):
assert name in SOLIDITY_FUNCTIONS assert name in SOLIDITY_FUNCTIONS
self._name = name self._name = name
self._return_type = [ElementaryType(x) for x in SOLIDITY_FUNCTIONS[self.name]]
@property @property
def name(self): def name(self):
@ -140,7 +146,11 @@ class SolidityFunction:
@property @property
def return_type(self): def return_type(self):
return [ElementaryType(x) for x in SOLIDITY_FUNCTIONS[self.name]] return self._return_type
@return_type.setter
def return_type(self, r):
self._return_type = r
def __str__(self): def __str__(self):
return self._name return self._name

@ -3,3 +3,4 @@ from .elementary_type import ElementaryType
from .function_type import FunctionType from .function_type import FunctionType
from .mapping_type import MappingType from .mapping_type import MappingType
from .user_defined_type import UserDefinedType from .user_defined_type import UserDefinedType
from .type_information import TypeInformation

@ -0,0 +1,23 @@
from slither.core.solidity_types.type import Type
# Use to model the Type(X) function, which returns an undefined type
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
class TypeInformation(Type):
def __init__(self, c):
from slither.core.declarations.contract import Contract
assert isinstance(c, (Contract))
super(TypeInformation, self).__init__()
self._type = c
@property
def type(self):
return self._type
def __str__(self):
return f'type({self.type.name})'
def __eq__(self, other):
if not isinstance(other, TypeInformation):
return False
return self.type == other.type

@ -6,7 +6,7 @@ from slither.core.declarations import (Contract, Enum, Event, Function,
from slither.core.expressions import Identifier, Literal from slither.core.expressions import Identifier, Literal
from slither.core.solidity_types import (ArrayType, ElementaryType, from slither.core.solidity_types import (ArrayType, ElementaryType,
FunctionType, MappingType, FunctionType, MappingType,
UserDefinedType) UserDefinedType, TypeInformation)
from slither.core.solidity_types.elementary_type import Int as ElementaryTypeInt from slither.core.solidity_types.elementary_type import Int as ElementaryTypeInt
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
@ -297,6 +297,44 @@ def propagate_type_and_convert_call(result, node):
idx = idx +1 idx = idx +1
return result return result
def _convert_type_contract(ir, slither):
assert isinstance(ir.variable_left.type, TypeInformation)
contract = ir.variable_left.type.type
if ir.variable_right == 'creationCode':
if slither.crytic_compile:
bytecode = slither.crytic_compile.bytecode_init(contract.name)
else:
logger.info(
'The codebase uses type(x).creationCode, but crytic-compile was not used. As a result, the bytecode cannot be found')
bytecode = "MISSING_BYTECODE"
assignment = Assignment(ir.lvalue,
Constant(str(bytecode)),
ElementaryType('bytes'))
assignment.lvalue.set_type(ElementaryType('bytes'))
return assignment
if ir.variable_right == 'runtimeCode':
if slither.crytic_compile:
bytecode = slither.crytic_compile.bytecode_runtime(contract.name)
else:
logger.info(
'The codebase uses type(x).runtimeCode, but crytic-compile was not used. As a result, the bytecode cannot be found')
bytecode = "MISSING_BYTECODE"
assignment = Assignment(ir.lvalue,
Constant(str(bytecode)),
ElementaryType('bytes'))
assignment.lvalue.set_type(ElementaryType('bytes'))
return assignment
if ir.variable_right == 'name':
assignment = Assignment(ir.lvalue,
Constant(contract.name),
ElementaryType('string'))
assignment.lvalue.set_type(ElementaryType('string'))
return assignment
raise SlithIRError(f'type({contract.name}).{ir.variable_right} is unknown')
def propagate_types(ir, node): def propagate_types(ir, node):
# propagate the type # propagate the type
using_for = node.function.contract.using_for using_for = node.function.contract.using_for
@ -398,6 +436,8 @@ def propagate_types(ir, node):
ElementaryType('bytes4')) ElementaryType('bytes4'))
assignment.lvalue.set_type(ElementaryType('bytes4')) assignment.lvalue.set_type(ElementaryType('bytes4'))
return assignment return assignment
if isinstance(ir.variable_left, TemporaryVariable) and isinstance(ir.variable_left.type, TypeInformation):
return _convert_type_contract(ir, node.function.slither)
left = ir.variable_left left = ir.variable_left
t = None t = None
if isinstance(left, (Variable, SolidityVariable)): if isinstance(left, (Variable, SolidityVariable)):
@ -447,6 +487,8 @@ def propagate_types(ir, node):
elif isinstance(ir, Send): elif isinstance(ir, Send):
ir.lvalue.set_type(ElementaryType('bool')) ir.lvalue.set_type(ElementaryType('bool'))
elif isinstance(ir, SolidityCall): elif isinstance(ir, SolidityCall):
if ir.function.name == 'type(address)':
ir.function.return_type = [TypeInformation(ir.arguments[0])]
return_type = ir.function.return_type return_type = ir.function.return_type
if len(return_type) == 1: if len(return_type) == 1:
ir.lvalue.set_type(return_type[0]) ir.lvalue.set_type(return_type[0])

Loading…
Cancel
Save