slither.slither
1import logging 2 3from crytic_compile import CryticCompile, InvalidCompilation 4 5 6from slither.core.compilation_unit import SlitherCompilationUnit 7from slither.core.slither_core import SlitherCore 8from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification 9from slither.exceptions import SlitherError 10from slither.printers.abstract_printer import AbstractPrinter 11from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc 12from slither.vyper_parsing.vyper_compilation_unit import VyperCompilationUnit 13from slither.utils.output import Output 14from slither.vyper_parsing.ast.ast import parse 15 16logger = logging.getLogger("Slither") 17logging.basicConfig() 18 19logger_detector = logging.getLogger("Detectors") 20logger_printer = logging.getLogger("Printers") 21 22 23def _check_common_things( 24 thing_name: str, cls: type, base_cls: type, instances_list: list[type[AbstractDetector]] 25) -> None: 26 if not issubclass(cls, base_cls) or cls is base_cls: 27 raise SlitherError( 28 f"You can't register {cls!r} as a {thing_name}. You need to pass a class that inherits from {base_cls.__name__}" 29 ) 30 31 if any(type(obj) is cls for obj in instances_list): 32 raise SlitherError(f"You can't register {cls!r} twice.") 33 34 35def _update_file_scopes( 36 sol_parser: SlitherCompilationUnitSolc, 37): 38 """ 39 Since all definitions in a file are exported by default, including definitions from its (transitive) dependencies, 40 we can identify all top level items that could possibly be referenced within the file from its exportedSymbols. 41 It is not as straightforward for user defined types and functions as well as aliasing. See add_accessible_scopes for more details. 42 """ 43 candidates = sol_parser.compilation_unit.scopes.values() 44 learned_something = False 45 # Because solc's import allows cycle in the import graph, iterate until we aren't adding new information to the scope. 46 while True: 47 for candidate in candidates: 48 learned_something |= candidate.add_accessible_scopes() 49 if not learned_something: 50 break 51 learned_something = False 52 53 for scope in candidates: 54 for refId in scope.exported_symbols: 55 if refId in sol_parser.contracts_by_id: 56 contract = sol_parser.contracts_by_id[refId] 57 scope.contracts[contract.name] = contract 58 elif refId in sol_parser.functions_by_id: 59 functions = sol_parser.functions_by_id[refId] 60 assert len(functions) == 1 61 scope.functions.add(functions[0]) 62 elif refId in sol_parser.imports_by_id: 63 import_directive = sol_parser.imports_by_id[refId] 64 scope.imports.add(import_directive) 65 elif refId in sol_parser.top_level_variables_by_id: 66 top_level_variable = sol_parser.top_level_variables_by_id[refId] 67 scope.variables[top_level_variable.name] = top_level_variable 68 elif refId in sol_parser.top_level_events_by_id: 69 top_level_event = sol_parser.top_level_events_by_id[refId] 70 scope.events.add(top_level_event) 71 elif refId in sol_parser.top_level_structures_by_id: 72 top_level_struct = sol_parser.top_level_structures_by_id[refId] 73 scope.structures[top_level_struct.name] = top_level_struct 74 elif refId in sol_parser.top_level_type_aliases_by_id: 75 top_level_type_alias = sol_parser.top_level_type_aliases_by_id[refId] 76 scope.type_aliases[top_level_type_alias.name] = top_level_type_alias 77 elif refId in sol_parser.top_level_enums_by_id: 78 top_level_enum = sol_parser.top_level_enums_by_id[refId] 79 scope.enums[top_level_enum.name] = top_level_enum 80 elif refId in sol_parser.top_level_errors_by_id: 81 top_level_custom_error = sol_parser.top_level_errors_by_id[refId] 82 scope.custom_errors.add(top_level_custom_error) 83 else: 84 logger.error( 85 f"Failed to resolved name for reference id {refId} in {scope.filename.absolute}." 86 ) 87 88 89class Slither(SlitherCore): 90 def __init__(self, target: str | CryticCompile, **kwargs) -> None: 91 """ 92 Args: 93 target (str | CryticCompile) 94 Keyword Args: 95 solc (str): solc binary location (default 'solc') 96 disable_solc_warnings (bool): True to disable solc warnings (default false) 97 solc_args (str): solc arguments (default '') 98 ast_format (str): ast format (default '--ast-compact-json') 99 filter_paths (list(str)): list of path to filter (default []) 100 triage_mode (bool): if true, switch to triage mode (default false) 101 exclude_dependencies (bool): if true, exclude results that are only related to dependencies 102 generate_patches (bool): if true, patches are generated (json output only) 103 change_line_prefix (str): Change the line prefix (default #) 104 for the displayed source codes (i.e. file.sol#1). 105 106 """ 107 super().__init__() 108 109 self._disallow_partial: bool = kwargs.get("disallow_partial", False) 110 self._skip_assembly: bool = kwargs.get("skip_assembly", False) 111 self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False) 112 113 self.line_prefix = kwargs.get("change_line_prefix", "#") 114 115 # Indicate if Codex related features should be used 116 self.codex_enabled = kwargs.get("codex", False) 117 self.codex_contracts = kwargs.get("codex_contracts", "all") 118 self.codex_model = kwargs.get("codex_model", "text-davinci-003") 119 self.codex_temperature = kwargs.get("codex_temperature", 0) 120 self.codex_max_tokens = kwargs.get("codex_max_tokens", 300) 121 self.codex_log = kwargs.get("codex_log", False) 122 self.codex_organization: str | None = kwargs.get("codex_organization") 123 124 self.no_fail = kwargs.get("no_fail", False) 125 126 self._parsers: list[SlitherCompilationUnitSolc] = [] 127 try: 128 if isinstance(target, CryticCompile): 129 crytic_compile = target 130 else: 131 crytic_compile = CryticCompile(target, **kwargs) 132 self._crytic_compile = crytic_compile 133 except InvalidCompilation as e: 134 raise SlitherError(f"Invalid compilation: \n{e!s}") 135 for compilation_unit in crytic_compile.compilation_units.values(): 136 compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit) 137 self._compilation_units.append(compilation_unit_slither) 138 139 if compilation_unit_slither.is_vyper: 140 vyper_parser = VyperCompilationUnit(compilation_unit_slither) 141 for path, ast in compilation_unit.asts.items(): 142 ast_nodes = parse(ast["ast"]) 143 vyper_parser.parse_module(ast_nodes, path) 144 self._parsers.append(vyper_parser) 145 else: 146 # Solidity specific 147 assert compilation_unit_slither.is_solidity 148 sol_parser = SlitherCompilationUnitSolc(compilation_unit_slither) 149 self._parsers.append(sol_parser) 150 for path, ast in compilation_unit.asts.items(): 151 sol_parser.parse_top_level_items(ast, path) 152 self.add_source_code(path) 153 154 for contract in sol_parser._underlying_contract_to_parser: 155 if contract.name.startswith("SlitherInternalTopLevelContract"): 156 raise SlitherError( 157 # region multi-line-string 158 """Your codebase has a contract named 'SlitherInternalTopLevelContract'. 159 Please rename it, this name is reserved for Slither's internals""" 160 # endregion multi-line 161 ) 162 sol_parser._contracts_by_id[contract.id] = contract 163 sol_parser._compilation_unit.contracts.append(contract) 164 165 _update_file_scopes(sol_parser) 166 167 if kwargs.get("generate_patches", False): 168 self.generate_patches = True 169 170 self._markdown_root = kwargs.get("markdown_root", "") 171 172 self._detectors = [] 173 self._printers = [] 174 175 filter_paths = kwargs.get("filter_paths", []) 176 for p in filter_paths: 177 self.add_path_to_filter(p) 178 179 include_paths = kwargs.get("include_paths", []) 180 for p in include_paths: 181 self.add_path_to_include(p) 182 183 self._exclude_dependencies = kwargs.get("exclude_dependencies", False) 184 185 triage_mode = kwargs.get("triage_mode", False) 186 triage_database = kwargs.get("triage_database", "slither.db.json") 187 self._triage_mode = triage_mode 188 self._previous_results_filename = triage_database 189 190 printers_to_run = kwargs.get("printers_to_run", "") 191 if printers_to_run == "echidna": 192 self.skip_data_dependency = True 193 194 # Used in inheritance-graph printer 195 self.include_interfaces = kwargs.get("include_interfaces", False) 196 197 self._init_parsing_and_analyses(kwargs.get("skip_analyze", False)) 198 199 def _init_parsing_and_analyses(self, skip_analyze: bool) -> None: 200 from slither.utils.timing import PhaseTimer 201 202 timer = PhaseTimer.get() 203 204 for parser in self._parsers: 205 try: 206 with timer.phase("parse_contracts"): 207 parser.parse_contracts() 208 except Exception as e: 209 if self.no_fail: 210 continue 211 raise e 212 213 # skip_analyze is only used for testing 214 if not skip_analyze: 215 for parser in self._parsers: 216 try: 217 with timer.phase("analyze_contracts"): 218 parser.analyze_contracts() 219 except Exception as e: 220 if self.no_fail: 221 continue 222 raise e 223 224 @property 225 def detectors(self): 226 return self._detectors 227 228 @property 229 def detectors_high(self): 230 return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH] 231 232 @property 233 def detectors_medium(self): 234 return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM] 235 236 @property 237 def detectors_low(self): 238 return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW] 239 240 @property 241 def detectors_informational(self): 242 return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL] 243 244 @property 245 def detectors_optimization(self): 246 return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION] 247 248 def register_detector(self, detector_class: type[AbstractDetector]) -> None: 249 """ 250 :param detector_class: Class inheriting from `AbstractDetector`. 251 """ 252 _check_common_things("detector", detector_class, AbstractDetector, self._detectors) 253 254 for compilation_unit in self.compilation_units: 255 instance = detector_class(compilation_unit, self, logger_detector) 256 self._detectors.append(instance) 257 258 def unregister_detector(self, detector_class: type[AbstractDetector]) -> None: 259 """ 260 :param detector_class: Class inheriting from `AbstractDetector`. 261 """ 262 263 for obj in self._detectors: 264 if isinstance(obj, detector_class): 265 self._detectors.remove(obj) 266 return 267 268 def register_printer(self, printer_class: type[AbstractPrinter]) -> None: 269 """ 270 :param printer_class: Class inheriting from `AbstractPrinter`. 271 """ 272 _check_common_things("printer", printer_class, AbstractPrinter, self._printers) 273 274 instance = printer_class(self, logger_printer) 275 self._printers.append(instance) 276 277 def unregister_printer(self, printer_class: type[AbstractPrinter]) -> None: 278 """ 279 :param printer_class: Class inheriting from `AbstractPrinter`. 280 """ 281 282 for obj in self._printers: 283 if isinstance(obj, printer_class): 284 self._printers.remove(obj) 285 return 286 287 def run_detectors(self) -> list[dict]: 288 """ 289 :return: List of registered detectors results. 290 """ 291 from slither.utils.timing import PhaseTimer 292 293 timer = PhaseTimer.get() 294 295 self.load_previous_results() 296 results = [] 297 for d in self._detectors: 298 with timer.phase(f"detector:{d.ARGUMENT}"): 299 results.append(d.detect()) 300 301 self.write_results_to_hide() 302 return results 303 304 def run_printers(self) -> list[Output]: 305 """ 306 :return: List of registered printers outputs. 307 """ 308 309 return [p.output(self._crytic_compile.target).data for p in self._printers] 310 311 @property 312 def triage_mode(self) -> bool: 313 return self._triage_mode
90class Slither(SlitherCore): 91 def __init__(self, target: str | CryticCompile, **kwargs) -> None: 92 """ 93 Args: 94 target (str | CryticCompile) 95 Keyword Args: 96 solc (str): solc binary location (default 'solc') 97 disable_solc_warnings (bool): True to disable solc warnings (default false) 98 solc_args (str): solc arguments (default '') 99 ast_format (str): ast format (default '--ast-compact-json') 100 filter_paths (list(str)): list of path to filter (default []) 101 triage_mode (bool): if true, switch to triage mode (default false) 102 exclude_dependencies (bool): if true, exclude results that are only related to dependencies 103 generate_patches (bool): if true, patches are generated (json output only) 104 change_line_prefix (str): Change the line prefix (default #) 105 for the displayed source codes (i.e. file.sol#1). 106 107 """ 108 super().__init__() 109 110 self._disallow_partial: bool = kwargs.get("disallow_partial", False) 111 self._skip_assembly: bool = kwargs.get("skip_assembly", False) 112 self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False) 113 114 self.line_prefix = kwargs.get("change_line_prefix", "#") 115 116 # Indicate if Codex related features should be used 117 self.codex_enabled = kwargs.get("codex", False) 118 self.codex_contracts = kwargs.get("codex_contracts", "all") 119 self.codex_model = kwargs.get("codex_model", "text-davinci-003") 120 self.codex_temperature = kwargs.get("codex_temperature", 0) 121 self.codex_max_tokens = kwargs.get("codex_max_tokens", 300) 122 self.codex_log = kwargs.get("codex_log", False) 123 self.codex_organization: str | None = kwargs.get("codex_organization") 124 125 self.no_fail = kwargs.get("no_fail", False) 126 127 self._parsers: list[SlitherCompilationUnitSolc] = [] 128 try: 129 if isinstance(target, CryticCompile): 130 crytic_compile = target 131 else: 132 crytic_compile = CryticCompile(target, **kwargs) 133 self._crytic_compile = crytic_compile 134 except InvalidCompilation as e: 135 raise SlitherError(f"Invalid compilation: \n{e!s}") 136 for compilation_unit in crytic_compile.compilation_units.values(): 137 compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit) 138 self._compilation_units.append(compilation_unit_slither) 139 140 if compilation_unit_slither.is_vyper: 141 vyper_parser = VyperCompilationUnit(compilation_unit_slither) 142 for path, ast in compilation_unit.asts.items(): 143 ast_nodes = parse(ast["ast"]) 144 vyper_parser.parse_module(ast_nodes, path) 145 self._parsers.append(vyper_parser) 146 else: 147 # Solidity specific 148 assert compilation_unit_slither.is_solidity 149 sol_parser = SlitherCompilationUnitSolc(compilation_unit_slither) 150 self._parsers.append(sol_parser) 151 for path, ast in compilation_unit.asts.items(): 152 sol_parser.parse_top_level_items(ast, path) 153 self.add_source_code(path) 154 155 for contract in sol_parser._underlying_contract_to_parser: 156 if contract.name.startswith("SlitherInternalTopLevelContract"): 157 raise SlitherError( 158 # region multi-line-string 159 """Your codebase has a contract named 'SlitherInternalTopLevelContract'. 160 Please rename it, this name is reserved for Slither's internals""" 161 # endregion multi-line 162 ) 163 sol_parser._contracts_by_id[contract.id] = contract 164 sol_parser._compilation_unit.contracts.append(contract) 165 166 _update_file_scopes(sol_parser) 167 168 if kwargs.get("generate_patches", False): 169 self.generate_patches = True 170 171 self._markdown_root = kwargs.get("markdown_root", "") 172 173 self._detectors = [] 174 self._printers = [] 175 176 filter_paths = kwargs.get("filter_paths", []) 177 for p in filter_paths: 178 self.add_path_to_filter(p) 179 180 include_paths = kwargs.get("include_paths", []) 181 for p in include_paths: 182 self.add_path_to_include(p) 183 184 self._exclude_dependencies = kwargs.get("exclude_dependencies", False) 185 186 triage_mode = kwargs.get("triage_mode", False) 187 triage_database = kwargs.get("triage_database", "slither.db.json") 188 self._triage_mode = triage_mode 189 self._previous_results_filename = triage_database 190 191 printers_to_run = kwargs.get("printers_to_run", "") 192 if printers_to_run == "echidna": 193 self.skip_data_dependency = True 194 195 # Used in inheritance-graph printer 196 self.include_interfaces = kwargs.get("include_interfaces", False) 197 198 self._init_parsing_and_analyses(kwargs.get("skip_analyze", False)) 199 200 def _init_parsing_and_analyses(self, skip_analyze: bool) -> None: 201 from slither.utils.timing import PhaseTimer 202 203 timer = PhaseTimer.get() 204 205 for parser in self._parsers: 206 try: 207 with timer.phase("parse_contracts"): 208 parser.parse_contracts() 209 except Exception as e: 210 if self.no_fail: 211 continue 212 raise e 213 214 # skip_analyze is only used for testing 215 if not skip_analyze: 216 for parser in self._parsers: 217 try: 218 with timer.phase("analyze_contracts"): 219 parser.analyze_contracts() 220 except Exception as e: 221 if self.no_fail: 222 continue 223 raise e 224 225 @property 226 def detectors(self): 227 return self._detectors 228 229 @property 230 def detectors_high(self): 231 return [d for d in self.detectors if d.IMPACT == DetectorClassification.HIGH] 232 233 @property 234 def detectors_medium(self): 235 return [d for d in self.detectors if d.IMPACT == DetectorClassification.MEDIUM] 236 237 @property 238 def detectors_low(self): 239 return [d for d in self.detectors if d.IMPACT == DetectorClassification.LOW] 240 241 @property 242 def detectors_informational(self): 243 return [d for d in self.detectors if d.IMPACT == DetectorClassification.INFORMATIONAL] 244 245 @property 246 def detectors_optimization(self): 247 return [d for d in self.detectors if d.IMPACT == DetectorClassification.OPTIMIZATION] 248 249 def register_detector(self, detector_class: type[AbstractDetector]) -> None: 250 """ 251 :param detector_class: Class inheriting from `AbstractDetector`. 252 """ 253 _check_common_things("detector", detector_class, AbstractDetector, self._detectors) 254 255 for compilation_unit in self.compilation_units: 256 instance = detector_class(compilation_unit, self, logger_detector) 257 self._detectors.append(instance) 258 259 def unregister_detector(self, detector_class: type[AbstractDetector]) -> None: 260 """ 261 :param detector_class: Class inheriting from `AbstractDetector`. 262 """ 263 264 for obj in self._detectors: 265 if isinstance(obj, detector_class): 266 self._detectors.remove(obj) 267 return 268 269 def register_printer(self, printer_class: type[AbstractPrinter]) -> None: 270 """ 271 :param printer_class: Class inheriting from `AbstractPrinter`. 272 """ 273 _check_common_things("printer", printer_class, AbstractPrinter, self._printers) 274 275 instance = printer_class(self, logger_printer) 276 self._printers.append(instance) 277 278 def unregister_printer(self, printer_class: type[AbstractPrinter]) -> None: 279 """ 280 :param printer_class: Class inheriting from `AbstractPrinter`. 281 """ 282 283 for obj in self._printers: 284 if isinstance(obj, printer_class): 285 self._printers.remove(obj) 286 return 287 288 def run_detectors(self) -> list[dict]: 289 """ 290 :return: List of registered detectors results. 291 """ 292 from slither.utils.timing import PhaseTimer 293 294 timer = PhaseTimer.get() 295 296 self.load_previous_results() 297 results = [] 298 for d in self._detectors: 299 with timer.phase(f"detector:{d.ARGUMENT}"): 300 results.append(d.detect()) 301 302 self.write_results_to_hide() 303 return results 304 305 def run_printers(self) -> list[Output]: 306 """ 307 :return: List of registered printers outputs. 308 """ 309 310 return [p.output(self._crytic_compile.target).data for p in self._printers] 311 312 @property 313 def triage_mode(self) -> bool: 314 return self._triage_mode
Slither static analyzer
91 def __init__(self, target: str | CryticCompile, **kwargs) -> None: 92 """ 93 Args: 94 target (str | CryticCompile) 95 Keyword Args: 96 solc (str): solc binary location (default 'solc') 97 disable_solc_warnings (bool): True to disable solc warnings (default false) 98 solc_args (str): solc arguments (default '') 99 ast_format (str): ast format (default '--ast-compact-json') 100 filter_paths (list(str)): list of path to filter (default []) 101 triage_mode (bool): if true, switch to triage mode (default false) 102 exclude_dependencies (bool): if true, exclude results that are only related to dependencies 103 generate_patches (bool): if true, patches are generated (json output only) 104 change_line_prefix (str): Change the line prefix (default #) 105 for the displayed source codes (i.e. file.sol#1). 106 107 """ 108 super().__init__() 109 110 self._disallow_partial: bool = kwargs.get("disallow_partial", False) 111 self._skip_assembly: bool = kwargs.get("skip_assembly", False) 112 self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False) 113 114 self.line_prefix = kwargs.get("change_line_prefix", "#") 115 116 # Indicate if Codex related features should be used 117 self.codex_enabled = kwargs.get("codex", False) 118 self.codex_contracts = kwargs.get("codex_contracts", "all") 119 self.codex_model = kwargs.get("codex_model", "text-davinci-003") 120 self.codex_temperature = kwargs.get("codex_temperature", 0) 121 self.codex_max_tokens = kwargs.get("codex_max_tokens", 300) 122 self.codex_log = kwargs.get("codex_log", False) 123 self.codex_organization: str | None = kwargs.get("codex_organization") 124 125 self.no_fail = kwargs.get("no_fail", False) 126 127 self._parsers: list[SlitherCompilationUnitSolc] = [] 128 try: 129 if isinstance(target, CryticCompile): 130 crytic_compile = target 131 else: 132 crytic_compile = CryticCompile(target, **kwargs) 133 self._crytic_compile = crytic_compile 134 except InvalidCompilation as e: 135 raise SlitherError(f"Invalid compilation: \n{e!s}") 136 for compilation_unit in crytic_compile.compilation_units.values(): 137 compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit) 138 self._compilation_units.append(compilation_unit_slither) 139 140 if compilation_unit_slither.is_vyper: 141 vyper_parser = VyperCompilationUnit(compilation_unit_slither) 142 for path, ast in compilation_unit.asts.items(): 143 ast_nodes = parse(ast["ast"]) 144 vyper_parser.parse_module(ast_nodes, path) 145 self._parsers.append(vyper_parser) 146 else: 147 # Solidity specific 148 assert compilation_unit_slither.is_solidity 149 sol_parser = SlitherCompilationUnitSolc(compilation_unit_slither) 150 self._parsers.append(sol_parser) 151 for path, ast in compilation_unit.asts.items(): 152 sol_parser.parse_top_level_items(ast, path) 153 self.add_source_code(path) 154 155 for contract in sol_parser._underlying_contract_to_parser: 156 if contract.name.startswith("SlitherInternalTopLevelContract"): 157 raise SlitherError( 158 # region multi-line-string 159 """Your codebase has a contract named 'SlitherInternalTopLevelContract'. 160 Please rename it, this name is reserved for Slither's internals""" 161 # endregion multi-line 162 ) 163 sol_parser._contracts_by_id[contract.id] = contract 164 sol_parser._compilation_unit.contracts.append(contract) 165 166 _update_file_scopes(sol_parser) 167 168 if kwargs.get("generate_patches", False): 169 self.generate_patches = True 170 171 self._markdown_root = kwargs.get("markdown_root", "") 172 173 self._detectors = [] 174 self._printers = [] 175 176 filter_paths = kwargs.get("filter_paths", []) 177 for p in filter_paths: 178 self.add_path_to_filter(p) 179 180 include_paths = kwargs.get("include_paths", []) 181 for p in include_paths: 182 self.add_path_to_include(p) 183 184 self._exclude_dependencies = kwargs.get("exclude_dependencies", False) 185 186 triage_mode = kwargs.get("triage_mode", False) 187 triage_database = kwargs.get("triage_database", "slither.db.json") 188 self._triage_mode = triage_mode 189 self._previous_results_filename = triage_database 190 191 printers_to_run = kwargs.get("printers_to_run", "") 192 if printers_to_run == "echidna": 193 self.skip_data_dependency = True 194 195 # Used in inheritance-graph printer 196 self.include_interfaces = kwargs.get("include_interfaces", False) 197 198 self._init_parsing_and_analyses(kwargs.get("skip_analyze", False))
Args: target (str | CryticCompile) Keyword Args: solc (str): solc binary location (default 'solc') disable_solc_warnings (bool): True to disable solc warnings (default false) solc_args (str): solc arguments (default '') ast_format (str): ast format (default '--ast-compact-json') filter_paths (list(str)): list of path to filter (default []) triage_mode (bool): if true, switch to triage mode (default false) exclude_dependencies (bool): if true, exclude results that are only related to dependencies generate_patches (bool): if true, patches are generated (json output only) change_line_prefix (str): Change the line prefix (default #) for the displayed source codes (i.e. file.sol#1).
249 def register_detector(self, detector_class: type[AbstractDetector]) -> None: 250 """ 251 :param detector_class: Class inheriting from `AbstractDetector`. 252 """ 253 _check_common_things("detector", detector_class, AbstractDetector, self._detectors) 254 255 for compilation_unit in self.compilation_units: 256 instance = detector_class(compilation_unit, self, logger_detector) 257 self._detectors.append(instance)
Parameters
- detector_class: Class inheriting from
AbstractDetector.
259 def unregister_detector(self, detector_class: type[AbstractDetector]) -> None: 260 """ 261 :param detector_class: Class inheriting from `AbstractDetector`. 262 """ 263 264 for obj in self._detectors: 265 if isinstance(obj, detector_class): 266 self._detectors.remove(obj) 267 return
Parameters
- detector_class: Class inheriting from
AbstractDetector.
269 def register_printer(self, printer_class: type[AbstractPrinter]) -> None: 270 """ 271 :param printer_class: Class inheriting from `AbstractPrinter`. 272 """ 273 _check_common_things("printer", printer_class, AbstractPrinter, self._printers) 274 275 instance = printer_class(self, logger_printer) 276 self._printers.append(instance)
Parameters
- printer_class: Class inheriting from
AbstractPrinter.
278 def unregister_printer(self, printer_class: type[AbstractPrinter]) -> None: 279 """ 280 :param printer_class: Class inheriting from `AbstractPrinter`. 281 """ 282 283 for obj in self._printers: 284 if isinstance(obj, printer_class): 285 self._printers.remove(obj) 286 return
Parameters
- printer_class: Class inheriting from
AbstractPrinter.
288 def run_detectors(self) -> list[dict]: 289 """ 290 :return: List of registered detectors results. 291 """ 292 from slither.utils.timing import PhaseTimer 293 294 timer = PhaseTimer.get() 295 296 self.load_previous_results() 297 results = [] 298 for d in self._detectors: 299 with timer.phase(f"detector:{d.ARGUMENT}"): 300 results.append(d.detect()) 301 302 self.write_results_to_hide() 303 return results
Returns
List of registered detectors results.
305 def run_printers(self) -> list[Output]: 306 """ 307 :return: List of registered printers outputs. 308 """ 309 310 return [p.output(self._crytic_compile.target).data for p in self._printers]
Returns
List of registered printers outputs.
Inherited Members
- slither.core.slither_core.SlitherCore
- sarif_input
- sarif_triage
- skip_data_dependency
- compilation_units
- add_compilation_unit
- contracts
- contracts_derived
- get_contract_from_name
- source_code
- filename
- add_source_code
- markdown_root
- print_functions
- offset_to_references
- offset_to_implementations
- offset_to_definitions
- offset_to_objects
- parse_ignore_comments
- has_ignore_comment
- valid_result
- load_previous_results
- load_previous_results_from_sarif
- write_results_to_hide
- save_results_to_hide
- add_path_to_filter
- add_path_to_include
- warn_unused_ignores
- get_unused_ignore_comments
- crytic_compile
- generate_patches
- disallow_partial
- skip_assembly
- show_ignore_findings