slither.detectors.abstract_detector
1import abc 2import re 3from logging import Logger 4from typing import Optional, List, TYPE_CHECKING, Dict, Union, Callable 5 6from slither.core.compilation_unit import SlitherCompilationUnit, Language 7from slither.core.declarations import Contract 8from slither.formatters.exceptions import FormatImpossible 9from slither.formatters.utils.patches import apply_patch, create_diff 10from slither.utils.colors import green, yellow, red 11from slither.utils.comparable_enum import ComparableEnum 12from slither.utils.output import Output, SupportedOutput 13 14if TYPE_CHECKING: 15 from slither import Slither 16 17 18class IncorrectDetectorInitialization(Exception): 19 pass 20 21 22class DetectorClassification(ComparableEnum): 23 HIGH = 0 24 MEDIUM = 1 25 LOW = 2 26 INFORMATIONAL = 3 27 OPTIMIZATION = 4 28 29 UNIMPLEMENTED = 999 30 31 32classification_colors: Dict[DetectorClassification, Callable[[str], str]] = { 33 DetectorClassification.INFORMATIONAL: green, 34 DetectorClassification.OPTIMIZATION: green, 35 DetectorClassification.LOW: green, 36 DetectorClassification.MEDIUM: yellow, 37 DetectorClassification.HIGH: red, 38} 39 40classification_txt = { 41 DetectorClassification.INFORMATIONAL: "Informational", 42 DetectorClassification.OPTIMIZATION: "Optimization", 43 DetectorClassification.LOW: "Low", 44 DetectorClassification.MEDIUM: "Medium", 45 DetectorClassification.HIGH: "High", 46} 47 48 49def make_solc_versions(minor: int, patch_min: int, patch_max: int) -> List[str]: 50 """ 51 Create a list of solc version: [0.minor.patch_min .... 0.minor.patch_max] 52 """ 53 return [f"0.{minor}.{x}" for x in range(patch_min, patch_max + 1)] 54 55 56ALL_SOLC_VERSIONS_04 = make_solc_versions(4, 0, 26) 57ALL_SOLC_VERSIONS_05 = make_solc_versions(5, 0, 17) 58ALL_SOLC_VERSIONS_06 = make_solc_versions(6, 0, 12) 59ALL_SOLC_VERSIONS_07 = make_solc_versions(7, 0, 6) 60# No VERSIONS_08 as it is still in dev 61 62DETECTOR_INFO = List[Union[str, SupportedOutput]] 63 64 65class AbstractDetector(metaclass=abc.ABCMeta): 66 ARGUMENT = "" # run the detector with slither.py --ARGUMENT 67 HELP = "" # help information 68 IMPACT: DetectorClassification = DetectorClassification.UNIMPLEMENTED 69 CONFIDENCE: DetectorClassification = DetectorClassification.UNIMPLEMENTED 70 71 WIKI = "" 72 73 WIKI_TITLE = "" 74 WIKI_DESCRIPTION = "" 75 WIKI_EXPLOIT_SCENARIO = "" 76 WIKI_RECOMMENDATION = "" 77 78 STANDARD_JSON = True 79 80 # list of vulnerable solc versions as strings (e.g. ["0.4.25", "0.5.0"]) 81 # If the detector is meant to run on all versions, use None 82 VULNERABLE_SOLC_VERSIONS: Optional[List[str]] = None 83 # If the detector is meant to run on all languages, use None 84 # Otherwise, use `solidity` or `vyper` 85 LANGUAGE: Optional[str] = None 86 87 def __init__( 88 self, compilation_unit: SlitherCompilationUnit, slither: "Slither", logger: Logger 89 ) -> None: 90 self.compilation_unit: SlitherCompilationUnit = compilation_unit 91 self.contracts: List[Contract] = compilation_unit.contracts 92 self.slither: "Slither" = slither 93 # self.filename = slither.filename 94 self.logger = logger 95 96 if not self.HELP: 97 raise IncorrectDetectorInitialization( 98 f"HELP is not initialized {self.__class__.__name__}" 99 ) 100 101 if not self.ARGUMENT: 102 raise IncorrectDetectorInitialization( 103 f"ARGUMENT is not initialized {self.__class__.__name__}" 104 ) 105 106 if not self.WIKI: 107 raise IncorrectDetectorInitialization( 108 f"WIKI is not initialized {self.__class__.__name__}" 109 ) 110 111 if not self.WIKI_TITLE: 112 raise IncorrectDetectorInitialization( 113 f"WIKI_TITLE is not initialized {self.__class__.__name__}" 114 ) 115 116 if not self.WIKI_DESCRIPTION: 117 raise IncorrectDetectorInitialization( 118 f"WIKI_DESCRIPTION is not initialized {self.__class__.__name__}" 119 ) 120 121 if not self.WIKI_EXPLOIT_SCENARIO and self.IMPACT not in [ 122 DetectorClassification.INFORMATIONAL, 123 DetectorClassification.OPTIMIZATION, 124 ]: 125 raise IncorrectDetectorInitialization( 126 f"WIKI_EXPLOIT_SCENARIO is not initialized {self.__class__.__name__}" 127 ) 128 129 if not self.WIKI_RECOMMENDATION: 130 raise IncorrectDetectorInitialization( 131 f"WIKI_RECOMMENDATION is not initialized {self.__class__.__name__}" 132 ) 133 134 if self.VULNERABLE_SOLC_VERSIONS is not None and not self.VULNERABLE_SOLC_VERSIONS: 135 raise IncorrectDetectorInitialization( 136 f"VULNERABLE_SOLC_VERSIONS should not be an empty list {self.__class__.__name__}" 137 ) 138 139 if self.LANGUAGE is not None and self.LANGUAGE not in [ 140 Language.SOLIDITY.value, 141 Language.VYPER.value, 142 ]: 143 raise IncorrectDetectorInitialization( 144 f"LANGUAGE should not be either 'solidity' or 'vyper' {self.__class__.__name__}" 145 ) 146 147 if re.match("^[a-zA-Z0-9_-]*$", self.ARGUMENT) is None: 148 raise IncorrectDetectorInitialization( 149 f"ARGUMENT has illegal character {self.__class__.__name__}" 150 ) 151 152 if self.IMPACT not in [ 153 DetectorClassification.LOW, 154 DetectorClassification.MEDIUM, 155 DetectorClassification.HIGH, 156 DetectorClassification.INFORMATIONAL, 157 DetectorClassification.OPTIMIZATION, 158 ]: 159 raise IncorrectDetectorInitialization( 160 f"IMPACT is not initialized {self.__class__.__name__}" 161 ) 162 163 if self.CONFIDENCE not in [ 164 DetectorClassification.LOW, 165 DetectorClassification.MEDIUM, 166 DetectorClassification.HIGH, 167 DetectorClassification.INFORMATIONAL, 168 DetectorClassification.OPTIMIZATION, 169 ]: 170 raise IncorrectDetectorInitialization( 171 f"CONFIDENCE is not initialized {self.__class__.__name__}" 172 ) 173 174 def _log(self, info: str) -> None: 175 if self.logger: 176 self.logger.info(self.color(info)) 177 178 def _is_applicable_detector(self) -> bool: 179 if self.VULNERABLE_SOLC_VERSIONS: 180 return ( 181 self.compilation_unit.is_solidity 182 and self.compilation_unit.solc_version in self.VULNERABLE_SOLC_VERSIONS 183 ) 184 if self.LANGUAGE: 185 return self.compilation_unit.language.value == self.LANGUAGE 186 return True 187 188 @abc.abstractmethod 189 def _detect(self) -> List[Output]: 190 """TODO Documentation""" 191 return [] 192 193 # pylint: disable=too-many-branches 194 def detect(self) -> List[Dict]: 195 results: List[Dict] = [] 196 197 # check solc version 198 if not self._is_applicable_detector(): 199 return results 200 201 # only keep valid result, and remove duplicate 202 # Keep only dictionaries 203 for r in [output.data for output in self._detect()]: 204 if self.compilation_unit.core.valid_result(r) and r not in results: 205 results.append(r) 206 if results and self.logger: 207 self._log_result(results) 208 if self.compilation_unit.core.generate_patches: 209 for result in results: 210 try: 211 self._format(self.compilation_unit, result) 212 if not "patches" in result: 213 continue 214 result["patches_diff"] = {} 215 for file in result["patches"]: 216 original_txt = self.compilation_unit.core.source_code[file].encode("utf8") 217 patched_txt = original_txt 218 offset = 0 219 patches = result["patches"][file] 220 patches.sort(key=lambda x: x["start"]) 221 if not all( 222 patches[i]["end"] <= patches[i + 1]["end"] 223 for i in range(len(patches) - 1) 224 ): 225 self._log( 226 f"Impossible to generate patch; patches collisions: {patches}" 227 ) 228 continue 229 for patch in patches: 230 patched_txt, offset = apply_patch(patched_txt, patch, offset) 231 diff = create_diff(self.compilation_unit, original_txt, patched_txt, file) 232 if not diff: 233 self._log(f"Impossible to generate patch; empty {result}") 234 else: 235 result["patches_diff"][file] = diff 236 237 except FormatImpossible as exception: 238 self._log(f'\nImpossible to patch:\n\t{result["description"]}\t{exception}') 239 240 if results and self.slither.triage_mode: 241 while True: 242 indexes = input( 243 f'Results to hide during next runs: "0,1,...,{len(results)}" or "All" (enter to not hide results):\n' 244 ) 245 if indexes == "All": 246 self.slither.save_results_to_hide(results) 247 return [] 248 if indexes == "": 249 return results 250 if indexes.startswith("["): 251 indexes = indexes[1:] 252 if indexes.endswith("]"): 253 indexes = indexes[:-1] 254 try: 255 indexes_converted = [int(i) for i in indexes.split(",")] 256 self.slither.save_results_to_hide( 257 [r for (idx, r) in enumerate(results) if idx in indexes_converted] 258 ) 259 return [r for (idx, r) in enumerate(results) if idx not in indexes_converted] 260 except ValueError: 261 self.logger.error(yellow("Malformed input. Example of valid input: 0,1,2,3")) 262 results = sorted(results, key=lambda x: x["id"]) 263 264 return results 265 266 @property 267 def color(self) -> Callable[[str], str]: 268 return classification_colors[self.IMPACT] 269 270 def generate_result( 271 self, 272 info: DETECTOR_INFO, 273 additional_fields: Optional[Dict] = None, 274 ) -> Output: 275 output = Output( 276 info, 277 additional_fields, 278 standard_format=self.STANDARD_JSON, 279 markdown_root=self.slither.markdown_root, 280 ) 281 282 output.data["check"] = self.ARGUMENT 283 output.data["impact"] = classification_txt[self.IMPACT] 284 output.data["confidence"] = classification_txt[self.CONFIDENCE] 285 286 return output 287 288 @staticmethod 289 def _format(_compilation_unit: SlitherCompilationUnit, _result: Dict) -> None: 290 """Implement format""" 291 return 292 293 def _log_result(self, results: List[Dict]) -> None: 294 info = "\n" 295 for idx, result in enumerate(results): 296 if self.slither.triage_mode: 297 info += f"{idx}: " 298 info += result["description"] 299 info += f"Reference: {self.WIKI}" 300 self._log(info)
class
IncorrectDetectorInitialization(builtins.Exception):
Common base class for all non-exit exceptions.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
23class DetectorClassification(ComparableEnum): 24 HIGH = 0 25 MEDIUM = 1 26 LOW = 2 27 INFORMATIONAL = 3 28 OPTIMIZATION = 4 29 30 UNIMPLEMENTED = 999
An enumeration.
Inherited Members
- enum.Enum
- name
- value
classification_colors: Dict[DetectorClassification, Callable[[str], str]] =
{3: functools.partial(<function colorize>, '\x1b[92m'), 4: functools.partial(<function colorize>, '\x1b[92m'), 2: functools.partial(<function colorize>, '\x1b[92m'), 1: functools.partial(<function colorize>, '\x1b[93m'), 0: functools.partial(<function colorize>, '\x1b[91m')}
classification_txt =
{3: 'Informational', 4: 'Optimization', 2: 'Low', 1: 'Medium', 0: 'High'}
def
make_solc_versions(minor: int, patch_min: int, patch_max: int) -> List[str]:
50def make_solc_versions(minor: int, patch_min: int, patch_max: int) -> List[str]: 51 """ 52 Create a list of solc version: [0.minor.patch_min .... 0.minor.patch_max] 53 """ 54 return [f"0.{minor}.{x}" for x in range(patch_min, patch_max + 1)]
Create a list of solc version: [0.minor.patch_min .... 0.minor.patch_max]
ALL_SOLC_VERSIONS_04 =
['0.4.0', '0.4.1', '0.4.2', '0.4.3', '0.4.4', '0.4.5', '0.4.6', '0.4.7', '0.4.8', '0.4.9', '0.4.10', '0.4.11', '0.4.12', '0.4.13', '0.4.14', '0.4.15', '0.4.16', '0.4.17', '0.4.18', '0.4.19', '0.4.20', '0.4.21', '0.4.22', '0.4.23', '0.4.24', '0.4.25', '0.4.26']
ALL_SOLC_VERSIONS_05 =
['0.5.0', '0.5.1', '0.5.2', '0.5.3', '0.5.4', '0.5.5', '0.5.6', '0.5.7', '0.5.8', '0.5.9', '0.5.10', '0.5.11', '0.5.12', '0.5.13', '0.5.14', '0.5.15', '0.5.16', '0.5.17']
ALL_SOLC_VERSIONS_06 =
['0.6.0', '0.6.1', '0.6.2', '0.6.3', '0.6.4', '0.6.5', '0.6.6', '0.6.7', '0.6.8', '0.6.9', '0.6.10', '0.6.11', '0.6.12']
ALL_SOLC_VERSIONS_07 =
['0.7.0', '0.7.1', '0.7.2', '0.7.3', '0.7.4', '0.7.5', '0.7.6']
DETECTOR_INFO =
typing.List[typing.Union[str, slither.core.variables.variable.Variable, slither.core.declarations.contract.Contract, slither.core.declarations.function.Function, slither.core.declarations.enum.Enum, slither.core.declarations.event.Event, slither.core.declarations.structure.Structure, slither.core.declarations.pragma_directive.Pragma, slither.core.cfg.node.Node]]
class
AbstractDetector:
66class AbstractDetector(metaclass=abc.ABCMeta): 67 ARGUMENT = "" # run the detector with slither.py --ARGUMENT 68 HELP = "" # help information 69 IMPACT: DetectorClassification = DetectorClassification.UNIMPLEMENTED 70 CONFIDENCE: DetectorClassification = DetectorClassification.UNIMPLEMENTED 71 72 WIKI = "" 73 74 WIKI_TITLE = "" 75 WIKI_DESCRIPTION = "" 76 WIKI_EXPLOIT_SCENARIO = "" 77 WIKI_RECOMMENDATION = "" 78 79 STANDARD_JSON = True 80 81 # list of vulnerable solc versions as strings (e.g. ["0.4.25", "0.5.0"]) 82 # If the detector is meant to run on all versions, use None 83 VULNERABLE_SOLC_VERSIONS: Optional[List[str]] = None 84 # If the detector is meant to run on all languages, use None 85 # Otherwise, use `solidity` or `vyper` 86 LANGUAGE: Optional[str] = None 87 88 def __init__( 89 self, compilation_unit: SlitherCompilationUnit, slither: "Slither", logger: Logger 90 ) -> None: 91 self.compilation_unit: SlitherCompilationUnit = compilation_unit 92 self.contracts: List[Contract] = compilation_unit.contracts 93 self.slither: "Slither" = slither 94 # self.filename = slither.filename 95 self.logger = logger 96 97 if not self.HELP: 98 raise IncorrectDetectorInitialization( 99 f"HELP is not initialized {self.__class__.__name__}" 100 ) 101 102 if not self.ARGUMENT: 103 raise IncorrectDetectorInitialization( 104 f"ARGUMENT is not initialized {self.__class__.__name__}" 105 ) 106 107 if not self.WIKI: 108 raise IncorrectDetectorInitialization( 109 f"WIKI is not initialized {self.__class__.__name__}" 110 ) 111 112 if not self.WIKI_TITLE: 113 raise IncorrectDetectorInitialization( 114 f"WIKI_TITLE is not initialized {self.__class__.__name__}" 115 ) 116 117 if not self.WIKI_DESCRIPTION: 118 raise IncorrectDetectorInitialization( 119 f"WIKI_DESCRIPTION is not initialized {self.__class__.__name__}" 120 ) 121 122 if not self.WIKI_EXPLOIT_SCENARIO and self.IMPACT not in [ 123 DetectorClassification.INFORMATIONAL, 124 DetectorClassification.OPTIMIZATION, 125 ]: 126 raise IncorrectDetectorInitialization( 127 f"WIKI_EXPLOIT_SCENARIO is not initialized {self.__class__.__name__}" 128 ) 129 130 if not self.WIKI_RECOMMENDATION: 131 raise IncorrectDetectorInitialization( 132 f"WIKI_RECOMMENDATION is not initialized {self.__class__.__name__}" 133 ) 134 135 if self.VULNERABLE_SOLC_VERSIONS is not None and not self.VULNERABLE_SOLC_VERSIONS: 136 raise IncorrectDetectorInitialization( 137 f"VULNERABLE_SOLC_VERSIONS should not be an empty list {self.__class__.__name__}" 138 ) 139 140 if self.LANGUAGE is not None and self.LANGUAGE not in [ 141 Language.SOLIDITY.value, 142 Language.VYPER.value, 143 ]: 144 raise IncorrectDetectorInitialization( 145 f"LANGUAGE should not be either 'solidity' or 'vyper' {self.__class__.__name__}" 146 ) 147 148 if re.match("^[a-zA-Z0-9_-]*$", self.ARGUMENT) is None: 149 raise IncorrectDetectorInitialization( 150 f"ARGUMENT has illegal character {self.__class__.__name__}" 151 ) 152 153 if self.IMPACT not in [ 154 DetectorClassification.LOW, 155 DetectorClassification.MEDIUM, 156 DetectorClassification.HIGH, 157 DetectorClassification.INFORMATIONAL, 158 DetectorClassification.OPTIMIZATION, 159 ]: 160 raise IncorrectDetectorInitialization( 161 f"IMPACT is not initialized {self.__class__.__name__}" 162 ) 163 164 if self.CONFIDENCE not in [ 165 DetectorClassification.LOW, 166 DetectorClassification.MEDIUM, 167 DetectorClassification.HIGH, 168 DetectorClassification.INFORMATIONAL, 169 DetectorClassification.OPTIMIZATION, 170 ]: 171 raise IncorrectDetectorInitialization( 172 f"CONFIDENCE is not initialized {self.__class__.__name__}" 173 ) 174 175 def _log(self, info: str) -> None: 176 if self.logger: 177 self.logger.info(self.color(info)) 178 179 def _is_applicable_detector(self) -> bool: 180 if self.VULNERABLE_SOLC_VERSIONS: 181 return ( 182 self.compilation_unit.is_solidity 183 and self.compilation_unit.solc_version in self.VULNERABLE_SOLC_VERSIONS 184 ) 185 if self.LANGUAGE: 186 return self.compilation_unit.language.value == self.LANGUAGE 187 return True 188 189 @abc.abstractmethod 190 def _detect(self) -> List[Output]: 191 """TODO Documentation""" 192 return [] 193 194 # pylint: disable=too-many-branches 195 def detect(self) -> List[Dict]: 196 results: List[Dict] = [] 197 198 # check solc version 199 if not self._is_applicable_detector(): 200 return results 201 202 # only keep valid result, and remove duplicate 203 # Keep only dictionaries 204 for r in [output.data for output in self._detect()]: 205 if self.compilation_unit.core.valid_result(r) and r not in results: 206 results.append(r) 207 if results and self.logger: 208 self._log_result(results) 209 if self.compilation_unit.core.generate_patches: 210 for result in results: 211 try: 212 self._format(self.compilation_unit, result) 213 if not "patches" in result: 214 continue 215 result["patches_diff"] = {} 216 for file in result["patches"]: 217 original_txt = self.compilation_unit.core.source_code[file].encode("utf8") 218 patched_txt = original_txt 219 offset = 0 220 patches = result["patches"][file] 221 patches.sort(key=lambda x: x["start"]) 222 if not all( 223 patches[i]["end"] <= patches[i + 1]["end"] 224 for i in range(len(patches) - 1) 225 ): 226 self._log( 227 f"Impossible to generate patch; patches collisions: {patches}" 228 ) 229 continue 230 for patch in patches: 231 patched_txt, offset = apply_patch(patched_txt, patch, offset) 232 diff = create_diff(self.compilation_unit, original_txt, patched_txt, file) 233 if not diff: 234 self._log(f"Impossible to generate patch; empty {result}") 235 else: 236 result["patches_diff"][file] = diff 237 238 except FormatImpossible as exception: 239 self._log(f'\nImpossible to patch:\n\t{result["description"]}\t{exception}') 240 241 if results and self.slither.triage_mode: 242 while True: 243 indexes = input( 244 f'Results to hide during next runs: "0,1,...,{len(results)}" or "All" (enter to not hide results):\n' 245 ) 246 if indexes == "All": 247 self.slither.save_results_to_hide(results) 248 return [] 249 if indexes == "": 250 return results 251 if indexes.startswith("["): 252 indexes = indexes[1:] 253 if indexes.endswith("]"): 254 indexes = indexes[:-1] 255 try: 256 indexes_converted = [int(i) for i in indexes.split(",")] 257 self.slither.save_results_to_hide( 258 [r for (idx, r) in enumerate(results) if idx in indexes_converted] 259 ) 260 return [r for (idx, r) in enumerate(results) if idx not in indexes_converted] 261 except ValueError: 262 self.logger.error(yellow("Malformed input. Example of valid input: 0,1,2,3")) 263 results = sorted(results, key=lambda x: x["id"]) 264 265 return results 266 267 @property 268 def color(self) -> Callable[[str], str]: 269 return classification_colors[self.IMPACT] 270 271 def generate_result( 272 self, 273 info: DETECTOR_INFO, 274 additional_fields: Optional[Dict] = None, 275 ) -> Output: 276 output = Output( 277 info, 278 additional_fields, 279 standard_format=self.STANDARD_JSON, 280 markdown_root=self.slither.markdown_root, 281 ) 282 283 output.data["check"] = self.ARGUMENT 284 output.data["impact"] = classification_txt[self.IMPACT] 285 output.data["confidence"] = classification_txt[self.CONFIDENCE] 286 287 return output 288 289 @staticmethod 290 def _format(_compilation_unit: SlitherCompilationUnit, _result: Dict) -> None: 291 """Implement format""" 292 return 293 294 def _log_result(self, results: List[Dict]) -> None: 295 info = "\n" 296 for idx, result in enumerate(results): 297 if self.slither.triage_mode: 298 info += f"{idx}: " 299 info += result["description"] 300 info += f"Reference: {self.WIKI}" 301 self._log(info)
compilation_unit: slither.core.compilation_unit.SlitherCompilationUnit
contracts: List[slither.core.declarations.contract.Contract]
slither: slither.slither.Slither
def
detect(self) -> List[Dict]:
195 def detect(self) -> List[Dict]: 196 results: List[Dict] = [] 197 198 # check solc version 199 if not self._is_applicable_detector(): 200 return results 201 202 # only keep valid result, and remove duplicate 203 # Keep only dictionaries 204 for r in [output.data for output in self._detect()]: 205 if self.compilation_unit.core.valid_result(r) and r not in results: 206 results.append(r) 207 if results and self.logger: 208 self._log_result(results) 209 if self.compilation_unit.core.generate_patches: 210 for result in results: 211 try: 212 self._format(self.compilation_unit, result) 213 if not "patches" in result: 214 continue 215 result["patches_diff"] = {} 216 for file in result["patches"]: 217 original_txt = self.compilation_unit.core.source_code[file].encode("utf8") 218 patched_txt = original_txt 219 offset = 0 220 patches = result["patches"][file] 221 patches.sort(key=lambda x: x["start"]) 222 if not all( 223 patches[i]["end"] <= patches[i + 1]["end"] 224 for i in range(len(patches) - 1) 225 ): 226 self._log( 227 f"Impossible to generate patch; patches collisions: {patches}" 228 ) 229 continue 230 for patch in patches: 231 patched_txt, offset = apply_patch(patched_txt, patch, offset) 232 diff = create_diff(self.compilation_unit, original_txt, patched_txt, file) 233 if not diff: 234 self._log(f"Impossible to generate patch; empty {result}") 235 else: 236 result["patches_diff"][file] = diff 237 238 except FormatImpossible as exception: 239 self._log(f'\nImpossible to patch:\n\t{result["description"]}\t{exception}') 240 241 if results and self.slither.triage_mode: 242 while True: 243 indexes = input( 244 f'Results to hide during next runs: "0,1,...,{len(results)}" or "All" (enter to not hide results):\n' 245 ) 246 if indexes == "All": 247 self.slither.save_results_to_hide(results) 248 return [] 249 if indexes == "": 250 return results 251 if indexes.startswith("["): 252 indexes = indexes[1:] 253 if indexes.endswith("]"): 254 indexes = indexes[:-1] 255 try: 256 indexes_converted = [int(i) for i in indexes.split(",")] 257 self.slither.save_results_to_hide( 258 [r for (idx, r) in enumerate(results) if idx in indexes_converted] 259 ) 260 return [r for (idx, r) in enumerate(results) if idx not in indexes_converted] 261 except ValueError: 262 self.logger.error(yellow("Malformed input. Example of valid input: 0,1,2,3")) 263 results = sorted(results, key=lambda x: x["id"]) 264 265 return results
def
generate_result( self, info: List[Union[str, slither.core.variables.variable.Variable, slither.core.declarations.contract.Contract, slither.core.declarations.function.Function, slither.core.declarations.enum.Enum, slither.core.declarations.event.Event, slither.core.declarations.structure.Structure, slither.core.declarations.pragma_directive.Pragma, slither.core.cfg.node.Node]], additional_fields: Union[Dict, NoneType] = None) -> slither.utils.output.Output:
271 def generate_result( 272 self, 273 info: DETECTOR_INFO, 274 additional_fields: Optional[Dict] = None, 275 ) -> Output: 276 output = Output( 277 info, 278 additional_fields, 279 standard_format=self.STANDARD_JSON, 280 markdown_root=self.slither.markdown_root, 281 ) 282 283 output.data["check"] = self.ARGUMENT 284 output.data["impact"] = classification_txt[self.IMPACT] 285 output.data["confidence"] = classification_txt[self.CONFIDENCE] 286 287 return output