@ -1,5 +1,7 @@
""" This module contains representation classes for Solidity files, contracts
""" This module contains representation classes for Solidity files, contracts
and source mappings . """
and source mappings . """
from typing import Dict , Set
import mythril . laser . ethereum . util as helper
import mythril . laser . ethereum . util as helper
from mythril . ethereum . evmcontract import EVMContract
from mythril . ethereum . evmcontract import EVMContract
from mythril . ethereum . util import get_solc_json
from mythril . ethereum . util import get_solc_json
@ -20,9 +22,16 @@ class SourceMapping:
class SolidityFile :
class SolidityFile :
""" Representation of a file containing Solidity code. """
""" Representation of a file containing Solidity code. """
def __init__ ( self , filename , data ) :
def __init__ ( self , filename : str , data : str , full_contract_source : Set [ str ] ) :
"""
Metadata class containing data regarding a specific solidity file
: param filename : The filename of the solidity file
: param data : The code of the solidity file
: param full_contract_source : The set of contract source mappings of all the contracts in the file
"""
self . filename = filename
self . filename = filename
self . data = data
self . data = data
self . full_contract_source = full_contract_source
class SourceCodeInfo :
class SourceCodeInfo :
@ -69,7 +78,12 @@ class SolidityContract(EVMContract):
for filename in data [ " sourceList " ] :
for filename in data [ " sourceList " ] :
with open ( filename , " r " , encoding = " utf-8 " ) as file :
with open ( filename , " r " , encoding = " utf-8 " ) as file :
code = file . read ( )
code = file . read ( )
self . solidity_files . append ( SolidityFile ( filename , code ) )
full_contract_sources = self . get_full_contract_sources (
data [ " sources " ] [ filename ] [ " AST " ]
)
self . solidity_files . append (
SolidityFile ( filename , code , full_contract_sources )
)
has_contract = False
has_contract = False
@ -117,6 +131,19 @@ class SolidityContract(EVMContract):
super ( ) . __init__ ( code , creation_code , name = name )
super ( ) . __init__ ( code , creation_code , name = name )
@staticmethod
def get_full_contract_sources ( ast : Dict ) - > Set [ str ] :
"""
Takes a solc AST and gets the src mappings for all the contracts defined in the top level of the ast
: param ast : AST of the contract
: return : The source map
"""
source_map = set ( )
for child in ast [ " children " ] :
if " contractKind " in child [ " attributes " ] :
source_map . add ( child [ " src " ] )
return source_map
def get_source_info ( self , address , constructor = False ) :
def get_source_info ( self , address , constructor = False ) :
"""
"""
@ -140,6 +167,26 @@ class SolidityContract(EVMContract):
lineno = mappings [ index ] . lineno
lineno = mappings [ index ] . lineno
return SourceCodeInfo ( filename , lineno , code , mappings [ index ] . solc_mapping )
return SourceCodeInfo ( filename , lineno , code , mappings [ index ] . solc_mapping )
def _is_autogenerated_code ( self , offset : int , length : int , file_index : int ) - > bool :
"""
Checks whether the code is autogenerated or not
: param offset : offset of the code
: param length : length of the code
: param file_index : file the code corresponds to
: return : True if the code is internally generated , else false
"""
# Handle internal compiler files
if file_index == - 1 :
return True
# Handle the common code src map for the entire code.
if (
" {} : {} : {} " . format ( offset , length , file_index )
in self . solidity_files [ file_index ] . full_contract_source
) :
return True
return False
def _get_solc_mappings ( self , srcmap , constructor = False ) :
def _get_solc_mappings ( self , srcmap , constructor = False ) :
"""
"""
@ -161,7 +208,8 @@ class SolidityContract(EVMContract):
if len ( mapping ) > 2 and len ( mapping [ 2 ] ) > 0 :
if len ( mapping ) > 2 and len ( mapping [ 2 ] ) > 0 :
idx = int ( mapping [ 2 ] )
idx = int ( mapping [ 2 ] )
if idx == - 1 :
if self . _is_autogenerated_code ( offset , length , idx ) :
lineno = None
lineno = None
else :
else :
lineno = (
lineno = (