def _compile_solidity(self): try: options = [] if self.allow_paths: options.append(F"--allow-paths {self.allow_paths}") com = CryticCompile(self.source, solc_remaps=self.remap, solc_args=' '.join(options)) contracts = self._extract_bin_obj(com) libs = com.contracts_names.difference(com.contracts_names_without_libraries) if libs: return self._link_libraries(self.source, libs) return contracts except InvalidCompilation as err: if not self.compilation_err: logging.critical("Solidity compilation failed. Please use -ce flag to see the detail.") if global_params.WEB: six.print_({"error": "Solidity compilation failed."}) else: logging.critical("solc output:\n" + self.source) logging.critical(err) logging.critical("Solidity compilation failed.") if global_params.WEB: six.print_({"error": err}) exit(1)
def __init__(self, target, **kwargs): ''' Args: target (str | list(json) | CryticCompile) Keyword Args: solc (str): solc binary location (default 'solc') disable_solc_warnings (bool): True to disable solc warnings (default false) solc_arguments (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) truffle_ignore (bool): ignore truffle.js presence (default false) truffle_build_directory (str): build truffle directory (default 'build/contracts') truffle_ignore_compile (bool): do not run truffle compile (default False) truffle_version (str): use a specific truffle version (default None) embark_ignore (bool): ignore embark.js presence (default false) embark_ignore_compile (bool): do not run embark build (default False) embark_overwrite_config (bool): overwrite original config file (default false) ''' # list of files provided (see --splitted option) if isinstance(target, list): self._init_from_list(target) elif isinstance(target, str) and target.endswith('.json'): self._init_from_raw_json(target) else: super(Slither, self).__init__('') try: if isinstance(target, CryticCompile): crytic_compile = target else: crytic_compile = CryticCompile(target, **kwargs) self._crytic_compile = crytic_compile except InvalidCompilation as e: raise SlitherError('Invalid compilation: \n' + str(e)) for path, ast in crytic_compile.asts.items(): self._parse_contracts_from_loaded_json(ast, path) self._add_source_code(path) if kwargs.get('generate_patches', False): self.generate_patches = True self._detectors = [] self._printers = [] filter_paths = kwargs.get('filter_paths', []) for p in filter_paths: self.add_path_to_filter(p) self._exclude_dependencies = kwargs.get('exclude_dependencies', False) triage_mode = kwargs.get('triage_mode', False) self._triage_mode = triage_mode self._analyze_contracts()
def __init__(self, contract, **kwargs): ''' Args: contract (str| list(json)) Keyword Args: solc (str): solc binary location (default 'solc') disable_solc_warnings (bool): True to disable solc warnings (default false) solc_argeuments (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) truffle_ignore (bool): ignore truffle.js presence (default false) truffle_build_directory (str): build truffle directory (default 'build/contracts') truffle_ignore_compile (bool): do not run truffle compile (default False) truffle_version (str): use a specific truffle version (default None) embark_ignore (bool): ignore embark.js presence (default false) embark_ignore_compile (bool): do not run embark build (default False) embark_overwrite_config (bool): overwrite original config file (default false) ''' truffle_ignore = kwargs.get('truffle_ignore', False) embark_ignore = kwargs.get('embark_ignore', False) # list of files provided (see --splitted option) if isinstance(contract, list): self._init_from_list(contract) elif contract.endswith('.json'): self._init_from_raw_json(contract) else: super(Slither, self).__init__('') try: cryticCompile = CryticCompile(contract, **kwargs) self._crytic_compile = cryticCompile except InvalidCompilation as e: logger.error('Invalid compilation') logger.error(e) exit(-1) for path, ast in cryticCompile.asts.items(): self._parse_contracts_from_loaded_json(ast, path) with open(path) as f: self.source_code[path] = f.read() self._detectors = [] self._printers = [] filter_paths = kwargs.get('filter_paths', []) for p in filter_paths: self.add_path_to_filter(p) triage_mode = kwargs.get('triage_mode', False) self._triage_mode = triage_mode self._analyze_contracts()
def _link_libraries(self, filename, libs): options = [] for idx, lib in enumerate(libs): lib_address = "0x" + hex(idx+1)[2:].zfill(40) options.append("--libraries %s:%s" % (lib, lib_address)) if self.allow_paths: options.append(F"--allow-paths {self.allow_paths}") com = CryticCompile(target=self.source, solc_args=' '.join(options), solc_remaps=self.remap) return self._extract_bin_obj(com)
def main(): l = logging.getLogger('evm-cfg-builder') l.setLevel(logging.INFO) args = parse_args() if args.perf: cp = cProfile.Profile() cp.enable() if is_supported(args.filename): filename = args.filename del args.filename try: cryticCompile = CryticCompile(filename, **vars(args)) for contract in cryticCompile.contracts_names: bytecode_init = cryticCompile.bytecode_init(contract) if bytecode_init: for signature, hash in cryticCompile.hashes(contract).items(): known_hashes[hash] = signature logger.info(f'Analyze {contract}') _run(bytecode_init, f'{filename}-{contract}-init', args) runtime_bytecode = cryticCompile.bytecode_runtime(contract) if runtime_bytecode: _run(runtime_bytecode, f'{filename}-{contract}-runtime', args) else: logger.info('Runtime bytecode not available') except InvalidCompilation as e: logger.error(e) else: with open(args.filename, 'rb') as f: bytecode = f.read() logger.info(f'Analyze {args.filename}') _run(bytecode, args.filename, args) if args.perf: cp.disable() stats = pstats.Stats(cp).sort_stats("cumtime") stats.print_stats()
def complie_solc(source, contract_name, compiler_version, remappings='', solc_args=''): """Function is used to compile solidity contract and return its trimmed bytecode. :param source: Path to contract file :param contract_name: Name of the contract whose bytecode is required :param compiler_version: Compiler version requirement of the contract file :param remappings: String containing library remappings required to compile contract :param solc_args: String containing additional compiler argument flags :return: Trimmed bytecode of the contract """ try: com = CryticCompile(source, solc_remaps=remappings, solc_solcs_select=compiler_version, solc_args=solc_args) return trim_bytecode(com.bytecode_runtime(contract_name), compiler_version) except InvalidCompilation as e: logging.exception(e) return None
def _generate_compile(test_item: Item, skip_existing=False): flavor = "legacy" if test_item.is_legacy else "compact" test_file = os.path.join(TEST_ROOT, f"{test_item.test_id}-{test_item.base_ver}.sol") expected_file = os.path.join( TEST_ROOT, "compile", f"{test_item.test_id}-{test_item.solc_ver}-{flavor}.zip" ) if skip_existing: if os.path.isfile(expected_file): return set_solc(test_item) cc = CryticCompile(test_file, solc_force_legacy_json=test_item.is_legacy) print(f"Compiled to {expected_file}") save_to_zip([cc], expected_file)
def load_from_zip(target: str) -> List["CryticCompile"]: """ Load a file from a zip :param target: :return: """ from crytic_compile.crytic_compile import CryticCompile compilations = [] with ZipFile(target, "r") as file_desc: for project in file_desc.namelist(): compilations.append( CryticCompile(str(file_desc.read(project)), compile_force_framework="archive")) return compilations
def main() -> None: l = logging.getLogger("evm-cfg-builder") l.setLevel(logging.INFO) args = parse_args() cp: Optional[cProfile.Profile] = None if args.perf: cp = cProfile.Profile() cp.enable() if is_supported(args.filename): filename = args.filename del args.filename try: cryticCompile = CryticCompile(filename, **vars(args)) for key, compilation_unit in cryticCompile.compilation_units.items( ): for contract in compilation_unit.contracts_names: bytecode_init = compilation_unit.bytecode_init(contract) if bytecode_init: for signature, hash_id in compilation_unit.hashes( contract).items(): known_hashes[hash_id] = signature logger.info(f"Analyze {contract}") _run(bytecode_init, f"{key}-{filename}-{contract}-init", args) runtime_bytecode = compilation_unit.bytecode_runtime( contract) if runtime_bytecode: _run(runtime_bytecode, f"{key}-{filename}-{contract}-runtime", args) else: logger.info("Runtime bytecode not available") except InvalidCompilation as e: logger.error(e) else: with open(args.filename, "rb") as f: bytecode = f.read() logger.info(f"Analyze {args.filename}") _run(bytecode, args.filename, args) if args.perf and cp: cp.disable() stats = pstats.Stats(cp).sort_stats("cumtime") stats.print_stats()
def load_from_zip(target: str) -> List["CryticCompile"]: """Load a file from a zip Args: target (str): path to the Returns: List[CryticCompile]: List of loaded projects """ # pylint: disable=import-outside-toplevel from crytic_compile.crytic_compile import CryticCompile compilations = [] with ZipFile(target, "r") as file_desc: for project in file_desc.namelist(): compilations.append( CryticCompile(_to_str(file_desc.read(project)), compile_force_framework="Archive")) return compilations
def _generate_compile(test_item: Test, skip_existing=False): for version, flavor in test_item.versions_with_flavors: test_file = os.path.join(TEST_ROOT, test_item.test_file) expected_file = os.path.join( TEST_ROOT, "compile", f"{test_item.test_file}-{version}-{flavor}.zip") if skip_existing: if os.path.isfile(expected_file): continue set_solc(version) print(f"Compiled to {expected_file}") cc = CryticCompile(test_file, solc_force_legacy_json=flavor == "legacy") # pylint: disable=no-member Path(expected_file).parents[0].mkdir(parents=True, exist_ok=True) save_to_zip([cc], expected_file)
def __init__(self, target, **kwargs): """ Args: target (str | list(json) | CryticCompile) Keyword Args: solc (str): solc binary location (default 'solc') disable_solc_warnings (bool): True to disable solc warnings (default false) solc_arguments (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) truffle_ignore (bool): ignore truffle.js presence (default false) truffle_build_directory (str): build truffle directory (default 'build/contracts') truffle_ignore_compile (bool): do not run truffle compile (default False) truffle_version (str): use a specific truffle version (default None) embark_ignore (bool): ignore embark.js presence (default false) embark_ignore_compile (bool): do not run embark build (default False) embark_overwrite_config (bool): overwrite original config file (default false) """ super().__init__() self._parser: FortressSolc # This could be another parser, like FortressVyper, interface needs to be determined self._disallow_partial: bool = kwargs.get("disallow_partial", False) self._skip_assembly: bool = kwargs.get("skip_assembly", False) # list of files provided (see --splitted option) if isinstance(target, list): self._init_from_list(target) elif isinstance(target, str) and target.endswith(".json"): self._init_from_raw_json(target) else: self._parser = FortressSolc("", self) try: if isinstance(target, CryticCompile): crytic_compile = target else: crytic_compile = CryticCompile(target, **kwargs) self._crytic_compile = crytic_compile except InvalidCompilation as e: # pylint: disable=raise-missing-from raise FortressError(f"Invalid compilation: \n{str(e)}") for path, ast in crytic_compile.asts.items(): self._parser.parse_contracts_from_loaded_json(ast, path) self.add_source_code(path) if kwargs.get("generate_patches", False): self.generate_patches = True self._markdown_root = kwargs.get("markdown_root", "") self._detectors = [] self._printers = [] filter_paths = kwargs.get("filter_paths", []) for p in filter_paths: self.add_path_to_filter(p) self._exclude_dependencies = kwargs.get("exclude_dependencies", False) triage_mode = kwargs.get("triage_mode", False) self._triage_mode = triage_mode self._parser.parse_contracts() # skip_analyze is only used for testing if not kwargs.get("skip_analyze", False): self._parser.analyze_contracts()
def __init__(self, target: Union[str, CryticCompile], **kwargs): """ 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_arguments (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) truffle_ignore (bool): ignore truffle.js presence (default false) truffle_build_directory (str): build truffle directory (default 'build/contracts') truffle_ignore_compile (bool): do not run truffle compile (default False) truffle_version (str): use a specific truffle version (default None) embark_ignore (bool): ignore embark.js presence (default false) embark_ignore_compile (bool): do not run embark build (default False) embark_overwrite_config (bool): overwrite original config file (default false) """ super().__init__() self._disallow_partial: bool = kwargs.get("disallow_partial", False) self._skip_assembly: bool = kwargs.get("skip_assembly", False) self._show_ignored_findings: bool = kwargs.get("show_ignored_findings", False) self._parsers: List[SlitherCompilationUnitSolc] = [] try: if isinstance(target, CryticCompile): crytic_compile = target else: crytic_compile = CryticCompile(target, **kwargs) self._crytic_compile = crytic_compile except InvalidCompilation as e: # pylint: disable=raise-missing-from raise SlitherError(f"Invalid compilation: \n{str(e)}") for compilation_unit in crytic_compile.compilation_units.values(): compilation_unit_slither = SlitherCompilationUnit(self, compilation_unit) self._compilation_units.append(compilation_unit_slither) parser = SlitherCompilationUnitSolc(compilation_unit_slither) self._parsers.append(parser) for path, ast in compilation_unit.asts.items(): parser.parse_top_level_from_loaded_json(ast, path) self.add_source_code(path) _update_file_scopes(compilation_unit_slither.scopes.values()) if kwargs.get("generate_patches", False): self.generate_patches = True self._markdown_root = kwargs.get("markdown_root", "") self._detectors = [] self._printers = [] filter_paths = kwargs.get("filter_paths", []) for p in filter_paths: self.add_path_to_filter(p) self._exclude_dependencies = kwargs.get("exclude_dependencies", False) triage_mode = kwargs.get("triage_mode", False) self._triage_mode = triage_mode for parser in self._parsers: parser.parse_contracts() # skip_analyze is only used for testing if not kwargs.get("skip_analyze", False): for parser in self._parsers: parser.analyze_contracts()
def _extract_bin_obj(self, com: CryticCompile): return [(com.contracts_filenames[name].absolute + ':' + name, com.bytecode_runtime(name)) for name in com.contracts_names if com.bytecode_runtime(name)]