slither.core.compilation_unit
1import math 2from enum import Enum 3from typing import TYPE_CHECKING 4 5from crytic_compile import CompilationUnit, CryticCompile 6from crytic_compile.compiler.compiler import CompilerVersion 7from crytic_compile.utils.naming import Filename 8 9from slither.core.context.context import Context 10from slither.core.declarations import ( 11 Contract, 12 Pragma, 13 Import, 14 Function, 15 Modifier, 16) 17from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel 18from slither.core.declarations.enum_top_level import EnumTopLevel 19from slither.core.declarations.event_top_level import EventTopLevel 20from slither.core.declarations.function_top_level import FunctionTopLevel 21from slither.core.declarations.structure_top_level import StructureTopLevel 22from slither.core.declarations.using_for_top_level import UsingForTopLevel 23from slither.core.scope.scope import FileScope 24from slither.core.solidity_types.type_alias import TypeAliasTopLevel 25from slither.core.variables.state_variable import StateVariable 26from slither.core.variables.top_level_variable import TopLevelVariable 27from slither.slithir.operations import InternalCall 28from slither.slithir.variables import Constant 29 30if TYPE_CHECKING: 31 from slither.core.slither_core import SlitherCore 32 33 34class Language(Enum): 35 SOLIDITY = "solidity" 36 VYPER = "vyper" 37 38 @staticmethod 39 def from_str(label: str): 40 if label == "solc": 41 return Language.SOLIDITY 42 if label == "vyper": 43 return Language.VYPER 44 45 raise ValueError(f"Unknown language: {label}") 46 47 48class SlitherCompilationUnit(Context): 49 def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None: 50 super().__init__() 51 52 self._core = core 53 self._crytic_compile_compilation_unit = crytic_compilation_unit 54 self._language = Language.from_str(crytic_compilation_unit.compiler_version.compiler) 55 56 # Top level object 57 self.contracts: list[Contract] = [] 58 self._structures_top_level: list[StructureTopLevel] = [] 59 self._enums_top_level: list[EnumTopLevel] = [] 60 self._events_top_level: list[EventTopLevel] = [] 61 self._variables_top_level: list[TopLevelVariable] = [] 62 self._functions_top_level: list[FunctionTopLevel] = [] 63 self._using_for_top_level: list[UsingForTopLevel] = [] 64 self._pragma_directives: list[Pragma] = [] 65 self._import_directives: list[Import] = [] 66 self._custom_errors: list[CustomErrorTopLevel] = [] 67 self._type_aliases: dict[str, TypeAliasTopLevel] = {} 68 69 self._all_functions: set[Function] = set() 70 self._all_modifiers: set[Modifier] = set() 71 72 # Memoize 73 self._all_state_variables: set[StateVariable] | None = None 74 75 self._persistent_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {} 76 self._transient_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {} 77 78 self._contract_with_missing_inheritance: set[Contract] = set() 79 80 # Reverse inheritance map: parent -> list of all derived contracts 81 self._derived_contracts_map: dict[Contract, list[Contract]] | None = None 82 83 self._source_units: dict[int, str] = {} 84 85 self.counter_slithir_tuple = 0 86 self.counter_slithir_temporary = 0 87 self.counter_slithir_reference = 0 88 89 self.scopes: dict[Filename, FileScope] = {} 90 91 # Cache for filename lookups: file_index -> (Filename, is_dependency) 92 # Used by _convert_source_mapping to avoid repeated expensive lookups 93 self._filename_lookup_cache: dict[int, tuple[Filename, bool]] = {} 94 95 @property 96 def core(self) -> "SlitherCore": 97 return self._core 98 99 @property 100 def source_units(self) -> dict[int, str]: 101 return self._source_units 102 103 # endregion 104 ################################################################################### 105 ################################################################################### 106 # region Compiler 107 ################################################################################### 108 ################################################################################### 109 @property 110 def language(self) -> Language: 111 return self._language 112 113 @property 114 def is_vyper(self) -> bool: 115 return self._language == Language.VYPER 116 117 @property 118 def is_solidity(self) -> bool: 119 return self._language == Language.SOLIDITY 120 121 @property 122 def compiler_version(self) -> CompilerVersion: 123 return self._crytic_compile_compilation_unit.compiler_version 124 125 @property 126 def solc_version(self) -> str: 127 # TODO: make version a non optional argument of compiler version in cc 128 return self._crytic_compile_compilation_unit.compiler_version.version # type:ignore 129 130 @property 131 def crytic_compile_compilation_unit(self) -> CompilationUnit: 132 return self._crytic_compile_compilation_unit 133 134 @property 135 def crytic_compile(self) -> CryticCompile: 136 return self._crytic_compile_compilation_unit.crytic_compile 137 138 # endregion 139 ################################################################################### 140 ################################################################################### 141 # region Pragma attributes 142 ################################################################################### 143 ################################################################################### 144 145 @property 146 def pragma_directives(self) -> list[Pragma]: 147 """list(core.declarations.Pragma): Pragma directives.""" 148 return self._pragma_directives 149 150 @property 151 def import_directives(self) -> list[Import]: 152 """list(core.declarations.Import): Import directives""" 153 return self._import_directives 154 155 # endregion 156 ################################################################################### 157 ################################################################################### 158 # region Contracts 159 ################################################################################### 160 ################################################################################### 161 162 @property 163 def contracts_derived(self) -> list[Contract]: 164 """list(Contract): List of contracts that are derived and not inherited.""" 165 inheritances = [x.inheritance for x in self.contracts] 166 inheritance = [item for sublist in inheritances for item in sublist] 167 return [c for c in self.contracts if c not in inheritance] 168 169 def get_contract_from_name(self, contract_name: str | Constant) -> list[Contract]: 170 """ 171 Return a list of contract from a name 172 Args: 173 contract_name (str): name of the contract 174 Returns: 175 List[Contract] 176 """ 177 return [c for c in self.contracts if c.name == contract_name] 178 179 # endregion 180 ################################################################################### 181 ################################################################################### 182 # region Functions and modifiers 183 ################################################################################### 184 ################################################################################### 185 186 @property 187 def functions(self) -> list[Function]: 188 return list(self._all_functions) 189 190 def add_function(self, func: Function) -> None: 191 self._all_functions.add(func) 192 193 @property 194 def modifiers(self) -> list[Modifier]: 195 return list(self._all_modifiers) 196 197 def add_modifier(self, modif: Modifier) -> None: 198 self._all_modifiers.add(modif) 199 200 @property 201 def functions_and_modifiers(self) -> list[Function]: 202 return self.functions + list(self.modifiers) 203 204 def propagate_function_calls(self) -> None: 205 """This info is used to compute the rvalues of Phi operations in `fix_phi` and ultimately 206 is responsible for the `read` property of Phi operations which is vital to 207 propagating taints inter-procedurally 208 """ 209 for f in self.functions_and_modifiers: 210 for node in f.nodes: 211 for ir in node.irs_ssa: 212 if isinstance(ir, InternalCall): 213 assert ir.function 214 ir.function.add_reachable_from_node(node, ir) 215 216 # endregion 217 ################################################################################### 218 ################################################################################### 219 # region Variables 220 ################################################################################### 221 ################################################################################### 222 223 @property 224 def state_variables(self) -> list[StateVariable]: 225 if self._all_state_variables is None: 226 state_variabless = [c.state_variables for c in self.contracts] 227 state_variables = [item for sublist in state_variabless for item in sublist] 228 self._all_state_variables = set(state_variables) 229 return list(self._all_state_variables) 230 231 # endregion 232 ################################################################################### 233 ################################################################################### 234 # region Top level 235 ################################################################################### 236 ################################################################################### 237 238 @property 239 def structures_top_level(self) -> list[StructureTopLevel]: 240 return self._structures_top_level 241 242 @property 243 def enums_top_level(self) -> list[EnumTopLevel]: 244 return self._enums_top_level 245 246 @property 247 def events_top_level(self) -> list[EventTopLevel]: 248 return self._events_top_level 249 250 @property 251 def variables_top_level(self) -> list[TopLevelVariable]: 252 return self._variables_top_level 253 254 @property 255 def functions_top_level(self) -> list[FunctionTopLevel]: 256 return self._functions_top_level 257 258 @property 259 def using_for_top_level(self) -> list[UsingForTopLevel]: 260 return self._using_for_top_level 261 262 @property 263 def custom_errors(self) -> list[CustomErrorTopLevel]: 264 return self._custom_errors 265 266 @property 267 def type_aliases(self) -> dict[str, TypeAliasTopLevel]: 268 return self._type_aliases 269 270 # endregion 271 ################################################################################### 272 ################################################################################### 273 # region Internals 274 ################################################################################### 275 ################################################################################### 276 277 @property 278 def contracts_with_missing_inheritance(self) -> set[Contract]: 279 return self._contract_with_missing_inheritance 280 281 def _build_derived_contracts_map(self) -> dict[Contract, list[Contract]]: 282 """Build reverse inheritance mapping for O(1) derived_contracts lookup.""" 283 from collections import defaultdict 284 285 derived_map: dict[Contract, list[Contract]] = defaultdict(list) 286 for contract in self.contracts: 287 for parent in contract.inheritance: 288 if contract not in derived_map[parent]: 289 derived_map[parent].append(contract) 290 return dict(derived_map) 291 292 @property 293 def derived_contracts_map(self) -> dict[Contract, list[Contract]]: 294 """Cached reverse inheritance map: parent contract -> list of all derived contracts.""" 295 if self._derived_contracts_map is None: 296 self._derived_contracts_map = self._build_derived_contracts_map() 297 return self._derived_contracts_map 298 299 # endregion 300 ################################################################################### 301 ################################################################################### 302 # region Scope 303 ################################################################################### 304 ################################################################################### 305 306 def get_scope(self, filename_str: str) -> FileScope: 307 filename = self._crytic_compile_compilation_unit.crytic_compile.filename_lookup( 308 filename_str 309 ) 310 311 if filename not in self.scopes: 312 self.scopes[filename] = FileScope(filename) 313 314 return self.scopes[filename] 315 316 # endregion 317 ################################################################################### 318 ################################################################################### 319 # region Storage Layouts 320 ################################################################################### 321 ################################################################################### 322 323 def compute_storage_layout(self) -> None: 324 assert self.is_solidity 325 326 for contract in self.contracts_derived: 327 self._compute_storage_layout( 328 contract.name, 329 contract.storage_variables_ordered, 330 False, 331 contract.custom_storage_layout, 332 ) 333 self._compute_storage_layout( 334 contract.name, contract.transient_variables_ordered, True, None 335 ) 336 337 def _compute_storage_layout( 338 self, 339 contract_name: str, 340 state_variables_ordered: list[StateVariable], 341 is_transient: bool, 342 custom_storage_layout: int | None, 343 ): 344 if is_transient: 345 slot = 0 346 self._transient_storage_layouts[contract_name] = {} 347 else: 348 slot = custom_storage_layout if custom_storage_layout else 0 349 self._persistent_storage_layouts[contract_name] = {} 350 351 offset = 0 352 for var in state_variables_ordered: 353 assert var.type 354 size, new_slot = var.type.storage_size 355 356 if new_slot: 357 if offset > 0: 358 slot += 1 359 offset = 0 360 elif size + offset > 32: 361 slot += 1 362 offset = 0 363 364 if is_transient: 365 self._transient_storage_layouts[contract_name][var.canonical_name] = ( 366 slot, 367 offset, 368 ) 369 else: 370 self._persistent_storage_layouts[contract_name][var.canonical_name] = ( 371 slot, 372 offset, 373 ) 374 375 if new_slot: 376 slot += math.ceil(size / 32) 377 else: 378 offset += size 379 380 def storage_layout_of(self, contract: Contract, var: StateVariable) -> tuple[int, int]: 381 if var.is_stored: 382 return self._persistent_storage_layouts[contract.name][var.canonical_name] 383 return self._transient_storage_layouts[contract.name][var.canonical_name] 384 385 # endregion
class
Language(enum.Enum):
35class Language(Enum): 36 SOLIDITY = "solidity" 37 VYPER = "vyper" 38 39 @staticmethod 40 def from_str(label: str): 41 if label == "solc": 42 return Language.SOLIDITY 43 if label == "vyper": 44 return Language.VYPER 45 46 raise ValueError(f"Unknown language: {label}")
An enumeration.
SOLIDITY =
<Language.SOLIDITY: 'solidity'>
VYPER =
<Language.VYPER: 'vyper'>
49class SlitherCompilationUnit(Context): 50 def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None: 51 super().__init__() 52 53 self._core = core 54 self._crytic_compile_compilation_unit = crytic_compilation_unit 55 self._language = Language.from_str(crytic_compilation_unit.compiler_version.compiler) 56 57 # Top level object 58 self.contracts: list[Contract] = [] 59 self._structures_top_level: list[StructureTopLevel] = [] 60 self._enums_top_level: list[EnumTopLevel] = [] 61 self._events_top_level: list[EventTopLevel] = [] 62 self._variables_top_level: list[TopLevelVariable] = [] 63 self._functions_top_level: list[FunctionTopLevel] = [] 64 self._using_for_top_level: list[UsingForTopLevel] = [] 65 self._pragma_directives: list[Pragma] = [] 66 self._import_directives: list[Import] = [] 67 self._custom_errors: list[CustomErrorTopLevel] = [] 68 self._type_aliases: dict[str, TypeAliasTopLevel] = {} 69 70 self._all_functions: set[Function] = set() 71 self._all_modifiers: set[Modifier] = set() 72 73 # Memoize 74 self._all_state_variables: set[StateVariable] | None = None 75 76 self._persistent_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {} 77 self._transient_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {} 78 79 self._contract_with_missing_inheritance: set[Contract] = set() 80 81 # Reverse inheritance map: parent -> list of all derived contracts 82 self._derived_contracts_map: dict[Contract, list[Contract]] | None = None 83 84 self._source_units: dict[int, str] = {} 85 86 self.counter_slithir_tuple = 0 87 self.counter_slithir_temporary = 0 88 self.counter_slithir_reference = 0 89 90 self.scopes: dict[Filename, FileScope] = {} 91 92 # Cache for filename lookups: file_index -> (Filename, is_dependency) 93 # Used by _convert_source_mapping to avoid repeated expensive lookups 94 self._filename_lookup_cache: dict[int, tuple[Filename, bool]] = {} 95 96 @property 97 def core(self) -> "SlitherCore": 98 return self._core 99 100 @property 101 def source_units(self) -> dict[int, str]: 102 return self._source_units 103 104 # endregion 105 ################################################################################### 106 ################################################################################### 107 # region Compiler 108 ################################################################################### 109 ################################################################################### 110 @property 111 def language(self) -> Language: 112 return self._language 113 114 @property 115 def is_vyper(self) -> bool: 116 return self._language == Language.VYPER 117 118 @property 119 def is_solidity(self) -> bool: 120 return self._language == Language.SOLIDITY 121 122 @property 123 def compiler_version(self) -> CompilerVersion: 124 return self._crytic_compile_compilation_unit.compiler_version 125 126 @property 127 def solc_version(self) -> str: 128 # TODO: make version a non optional argument of compiler version in cc 129 return self._crytic_compile_compilation_unit.compiler_version.version # type:ignore 130 131 @property 132 def crytic_compile_compilation_unit(self) -> CompilationUnit: 133 return self._crytic_compile_compilation_unit 134 135 @property 136 def crytic_compile(self) -> CryticCompile: 137 return self._crytic_compile_compilation_unit.crytic_compile 138 139 # endregion 140 ################################################################################### 141 ################################################################################### 142 # region Pragma attributes 143 ################################################################################### 144 ################################################################################### 145 146 @property 147 def pragma_directives(self) -> list[Pragma]: 148 """list(core.declarations.Pragma): Pragma directives.""" 149 return self._pragma_directives 150 151 @property 152 def import_directives(self) -> list[Import]: 153 """list(core.declarations.Import): Import directives""" 154 return self._import_directives 155 156 # endregion 157 ################################################################################### 158 ################################################################################### 159 # region Contracts 160 ################################################################################### 161 ################################################################################### 162 163 @property 164 def contracts_derived(self) -> list[Contract]: 165 """list(Contract): List of contracts that are derived and not inherited.""" 166 inheritances = [x.inheritance for x in self.contracts] 167 inheritance = [item for sublist in inheritances for item in sublist] 168 return [c for c in self.contracts if c not in inheritance] 169 170 def get_contract_from_name(self, contract_name: str | Constant) -> list[Contract]: 171 """ 172 Return a list of contract from a name 173 Args: 174 contract_name (str): name of the contract 175 Returns: 176 List[Contract] 177 """ 178 return [c for c in self.contracts if c.name == contract_name] 179 180 # endregion 181 ################################################################################### 182 ################################################################################### 183 # region Functions and modifiers 184 ################################################################################### 185 ################################################################################### 186 187 @property 188 def functions(self) -> list[Function]: 189 return list(self._all_functions) 190 191 def add_function(self, func: Function) -> None: 192 self._all_functions.add(func) 193 194 @property 195 def modifiers(self) -> list[Modifier]: 196 return list(self._all_modifiers) 197 198 def add_modifier(self, modif: Modifier) -> None: 199 self._all_modifiers.add(modif) 200 201 @property 202 def functions_and_modifiers(self) -> list[Function]: 203 return self.functions + list(self.modifiers) 204 205 def propagate_function_calls(self) -> None: 206 """This info is used to compute the rvalues of Phi operations in `fix_phi` and ultimately 207 is responsible for the `read` property of Phi operations which is vital to 208 propagating taints inter-procedurally 209 """ 210 for f in self.functions_and_modifiers: 211 for node in f.nodes: 212 for ir in node.irs_ssa: 213 if isinstance(ir, InternalCall): 214 assert ir.function 215 ir.function.add_reachable_from_node(node, ir) 216 217 # endregion 218 ################################################################################### 219 ################################################################################### 220 # region Variables 221 ################################################################################### 222 ################################################################################### 223 224 @property 225 def state_variables(self) -> list[StateVariable]: 226 if self._all_state_variables is None: 227 state_variabless = [c.state_variables for c in self.contracts] 228 state_variables = [item for sublist in state_variabless for item in sublist] 229 self._all_state_variables = set(state_variables) 230 return list(self._all_state_variables) 231 232 # endregion 233 ################################################################################### 234 ################################################################################### 235 # region Top level 236 ################################################################################### 237 ################################################################################### 238 239 @property 240 def structures_top_level(self) -> list[StructureTopLevel]: 241 return self._structures_top_level 242 243 @property 244 def enums_top_level(self) -> list[EnumTopLevel]: 245 return self._enums_top_level 246 247 @property 248 def events_top_level(self) -> list[EventTopLevel]: 249 return self._events_top_level 250 251 @property 252 def variables_top_level(self) -> list[TopLevelVariable]: 253 return self._variables_top_level 254 255 @property 256 def functions_top_level(self) -> list[FunctionTopLevel]: 257 return self._functions_top_level 258 259 @property 260 def using_for_top_level(self) -> list[UsingForTopLevel]: 261 return self._using_for_top_level 262 263 @property 264 def custom_errors(self) -> list[CustomErrorTopLevel]: 265 return self._custom_errors 266 267 @property 268 def type_aliases(self) -> dict[str, TypeAliasTopLevel]: 269 return self._type_aliases 270 271 # endregion 272 ################################################################################### 273 ################################################################################### 274 # region Internals 275 ################################################################################### 276 ################################################################################### 277 278 @property 279 def contracts_with_missing_inheritance(self) -> set[Contract]: 280 return self._contract_with_missing_inheritance 281 282 def _build_derived_contracts_map(self) -> dict[Contract, list[Contract]]: 283 """Build reverse inheritance mapping for O(1) derived_contracts lookup.""" 284 from collections import defaultdict 285 286 derived_map: dict[Contract, list[Contract]] = defaultdict(list) 287 for contract in self.contracts: 288 for parent in contract.inheritance: 289 if contract not in derived_map[parent]: 290 derived_map[parent].append(contract) 291 return dict(derived_map) 292 293 @property 294 def derived_contracts_map(self) -> dict[Contract, list[Contract]]: 295 """Cached reverse inheritance map: parent contract -> list of all derived contracts.""" 296 if self._derived_contracts_map is None: 297 self._derived_contracts_map = self._build_derived_contracts_map() 298 return self._derived_contracts_map 299 300 # endregion 301 ################################################################################### 302 ################################################################################### 303 # region Scope 304 ################################################################################### 305 ################################################################################### 306 307 def get_scope(self, filename_str: str) -> FileScope: 308 filename = self._crytic_compile_compilation_unit.crytic_compile.filename_lookup( 309 filename_str 310 ) 311 312 if filename not in self.scopes: 313 self.scopes[filename] = FileScope(filename) 314 315 return self.scopes[filename] 316 317 # endregion 318 ################################################################################### 319 ################################################################################### 320 # region Storage Layouts 321 ################################################################################### 322 ################################################################################### 323 324 def compute_storage_layout(self) -> None: 325 assert self.is_solidity 326 327 for contract in self.contracts_derived: 328 self._compute_storage_layout( 329 contract.name, 330 contract.storage_variables_ordered, 331 False, 332 contract.custom_storage_layout, 333 ) 334 self._compute_storage_layout( 335 contract.name, contract.transient_variables_ordered, True, None 336 ) 337 338 def _compute_storage_layout( 339 self, 340 contract_name: str, 341 state_variables_ordered: list[StateVariable], 342 is_transient: bool, 343 custom_storage_layout: int | None, 344 ): 345 if is_transient: 346 slot = 0 347 self._transient_storage_layouts[contract_name] = {} 348 else: 349 slot = custom_storage_layout if custom_storage_layout else 0 350 self._persistent_storage_layouts[contract_name] = {} 351 352 offset = 0 353 for var in state_variables_ordered: 354 assert var.type 355 size, new_slot = var.type.storage_size 356 357 if new_slot: 358 if offset > 0: 359 slot += 1 360 offset = 0 361 elif size + offset > 32: 362 slot += 1 363 offset = 0 364 365 if is_transient: 366 self._transient_storage_layouts[contract_name][var.canonical_name] = ( 367 slot, 368 offset, 369 ) 370 else: 371 self._persistent_storage_layouts[contract_name][var.canonical_name] = ( 372 slot, 373 offset, 374 ) 375 376 if new_slot: 377 slot += math.ceil(size / 32) 378 else: 379 offset += size 380 381 def storage_layout_of(self, contract: Contract, var: StateVariable) -> tuple[int, int]: 382 if var.is_stored: 383 return self._persistent_storage_layouts[contract.name][var.canonical_name] 384 return self._transient_storage_layouts[contract.name][var.canonical_name] 385 386 # endregion
SlitherCompilationUnit( core: slither.core.slither_core.SlitherCore, crytic_compilation_unit: crytic_compile.compilation_unit.CompilationUnit)
50 def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None: 51 super().__init__() 52 53 self._core = core 54 self._crytic_compile_compilation_unit = crytic_compilation_unit 55 self._language = Language.from_str(crytic_compilation_unit.compiler_version.compiler) 56 57 # Top level object 58 self.contracts: list[Contract] = [] 59 self._structures_top_level: list[StructureTopLevel] = [] 60 self._enums_top_level: list[EnumTopLevel] = [] 61 self._events_top_level: list[EventTopLevel] = [] 62 self._variables_top_level: list[TopLevelVariable] = [] 63 self._functions_top_level: list[FunctionTopLevel] = [] 64 self._using_for_top_level: list[UsingForTopLevel] = [] 65 self._pragma_directives: list[Pragma] = [] 66 self._import_directives: list[Import] = [] 67 self._custom_errors: list[CustomErrorTopLevel] = [] 68 self._type_aliases: dict[str, TypeAliasTopLevel] = {} 69 70 self._all_functions: set[Function] = set() 71 self._all_modifiers: set[Modifier] = set() 72 73 # Memoize 74 self._all_state_variables: set[StateVariable] | None = None 75 76 self._persistent_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {} 77 self._transient_storage_layouts: dict[str, dict[str, tuple[int, int]]] = {} 78 79 self._contract_with_missing_inheritance: set[Contract] = set() 80 81 # Reverse inheritance map: parent -> list of all derived contracts 82 self._derived_contracts_map: dict[Contract, list[Contract]] | None = None 83 84 self._source_units: dict[int, str] = {} 85 86 self.counter_slithir_tuple = 0 87 self.counter_slithir_temporary = 0 88 self.counter_slithir_reference = 0 89 90 self.scopes: dict[Filename, FileScope] = {} 91 92 # Cache for filename lookups: file_index -> (Filename, is_dependency) 93 # Used by _convert_source_mapping to avoid repeated expensive lookups 94 self._filename_lookup_cache: dict[int, tuple[Filename, bool]] = {}
contracts: list[slither.core.declarations.contract.Contract]
scopes: dict[crytic_compile.utils.naming.Filename, slither.core.scope.scope.FileScope]
pragma_directives: list[slither.core.declarations.pragma_directive.Pragma]
146 @property 147 def pragma_directives(self) -> list[Pragma]: 148 """list(core.declarations.Pragma): Pragma directives.""" 149 return self._pragma_directives
list(core.declarations.Pragma): Pragma directives.
import_directives: list[slither.core.declarations.import_directive.Import]
151 @property 152 def import_directives(self) -> list[Import]: 153 """list(core.declarations.Import): Import directives""" 154 return self._import_directives
list(core.declarations.Import): Import directives
contracts_derived: list[slither.core.declarations.contract.Contract]
163 @property 164 def contracts_derived(self) -> list[Contract]: 165 """list(Contract): List of contracts that are derived and not inherited.""" 166 inheritances = [x.inheritance for x in self.contracts] 167 inheritance = [item for sublist in inheritances for item in sublist] 168 return [c for c in self.contracts if c not in inheritance]
list(Contract): List of contracts that are derived and not inherited.
def
get_contract_from_name( self, contract_name: str | slither.slithir.variables.constant.Constant) -> list[slither.core.declarations.contract.Contract]:
170 def get_contract_from_name(self, contract_name: str | Constant) -> list[Contract]: 171 """ 172 Return a list of contract from a name 173 Args: 174 contract_name (str): name of the contract 175 Returns: 176 List[Contract] 177 """ 178 return [c for c in self.contracts if c.name == contract_name]
Return a list of contract from a name Args: contract_name (str): name of the contract Returns: List[Contract]
functions: list[slither.core.declarations.function.Function]
modifiers: list[slither.core.declarations.modifier.Modifier]
functions_and_modifiers: list[slither.core.declarations.function.Function]
def
propagate_function_calls(self) -> None:
205 def propagate_function_calls(self) -> None: 206 """This info is used to compute the rvalues of Phi operations in `fix_phi` and ultimately 207 is responsible for the `read` property of Phi operations which is vital to 208 propagating taints inter-procedurally 209 """ 210 for f in self.functions_and_modifiers: 211 for node in f.nodes: 212 for ir in node.irs_ssa: 213 if isinstance(ir, InternalCall): 214 assert ir.function 215 ir.function.add_reachable_from_node(node, ir)
This info is used to compute the rvalues of Phi operations in fix_phi and ultimately
is responsible for the read property of Phi operations which is vital to
propagating taints inter-procedurally
state_variables: list[slither.core.variables.state_variable.StateVariable]
224 @property 225 def state_variables(self) -> list[StateVariable]: 226 if self._all_state_variables is None: 227 state_variabless = [c.state_variables for c in self.contracts] 228 state_variables = [item for sublist in state_variabless for item in sublist] 229 self._all_state_variables = set(state_variables) 230 return list(self._all_state_variables)
structures_top_level: list[slither.core.declarations.structure_top_level.StructureTopLevel]
enums_top_level: list[slither.core.declarations.enum_top_level.EnumTopLevel]
events_top_level: list[slither.core.declarations.event_top_level.EventTopLevel]
variables_top_level: list[slither.core.variables.top_level_variable.TopLevelVariable]
functions_top_level: list[slither.core.declarations.function_top_level.FunctionTopLevel]
using_for_top_level: list[slither.core.declarations.using_for_top_level.UsingForTopLevel]
custom_errors: list[slither.core.declarations.custom_error_top_level.CustomErrorTopLevel]
type_aliases: dict[str, slither.core.solidity_types.type_alias.TypeAliasTopLevel]
contracts_with_missing_inheritance: set[slither.core.declarations.contract.Contract]
derived_contracts_map: dict[slither.core.declarations.contract.Contract, list[slither.core.declarations.contract.Contract]]
293 @property 294 def derived_contracts_map(self) -> dict[Contract, list[Contract]]: 295 """Cached reverse inheritance map: parent contract -> list of all derived contracts.""" 296 if self._derived_contracts_map is None: 297 self._derived_contracts_map = self._build_derived_contracts_map() 298 return self._derived_contracts_map
Cached reverse inheritance map: parent contract -> list of all derived contracts.
def
compute_storage_layout(self) -> None:
324 def compute_storage_layout(self) -> None: 325 assert self.is_solidity 326 327 for contract in self.contracts_derived: 328 self._compute_storage_layout( 329 contract.name, 330 contract.storage_variables_ordered, 331 False, 332 contract.custom_storage_layout, 333 ) 334 self._compute_storage_layout( 335 contract.name, contract.transient_variables_ordered, True, None 336 )
def
storage_layout_of( self, contract: slither.core.declarations.contract.Contract, var: slither.core.variables.state_variable.StateVariable) -> tuple[int, int]: