def pre_analyze(params): action, context, analyzer_config_map, skip_handler, \ ctu_data, statistics_data = params analyzer_environment = analyzer_env.get_check_env( context.path_env_extra, context.ld_lib_path_extra) progress_checked_num.value += 1 for source in action.sources: if skip_handler and skip_handler.should_skip(source): continue if action.analyzer_type != analyzer_types.CLANG_SA: continue _, source_filename = os.path.split(source) source = util.escape_source_path(source) LOG.info("[%d/%d] %s" % (progress_checked_num.value, progress_actions.value, source_filename)) config = analyzer_config_map.get(analyzer_types.CLANG_SA) try: if ctu_data: LOG.debug("running CTU pre analysis") ctu_temp_fnmap_folder = ctu_data.get('ctu_temp_fnmap_folder') triple_arch = \ ctu_triple_arch.get_triple_arch(action, source, config, analyzer_environment) if not config.ctu_in_memory: ctu_manager.generate_ast(triple_arch, action, source, config, analyzer_environment) ctu_manager.map_functions(triple_arch, action, source, config, analyzer_environment, context.ctu_func_map_cmd, ctu_temp_fnmap_folder) except Exception as ex: LOG.debug_analyzer(str(ex)) traceback.print_exc(file=sys.stdout) raise try: if statistics_data: LOG.debug("running statistics pre analysis") collect_statistics(action, source, config, analyzer_environment, statistics_data) except Exception as ex: LOG.debug_analyzer(str(ex)) traceback.print_exc(file=sys.stdout) raise
def check(check_data): """ Invoke clang with an action which called by processes. Different analyzer object belongs to for each build action. skiplist handler is None if no skip file was configured. """ actions_map, action, context, analyzer_config_map, \ output_dir, skip_handler, quiet_output_on_stdout, \ capture_analysis_output, analysis_timeout, \ analyzer_environment, ctu_reanalyze_on_failure, \ output_dirs, statistics_data = check_data skipped = False reanalyzed = False failed_dir = output_dirs["failed"] success_dir = output_dirs["success"] try: # If one analysis fails the check fails. return_codes = 0 skipped = False result_file = '' for source in action.sources: # If there is no skiplist handler there was no skip list file # in the command line. # C++ file skipping is handled here. source_file_name = os.path.basename(source) if skip_handler and skip_handler.should_skip(source): LOG.debug_analyzer(source_file_name + ' is skipped') skipped = True continue source = util.escape_source_path(source) source_analyzer, analyzer_cmd, rh, reanalyzed = \ prepare_check(source, action, analyzer_config_map, output_dir, context.severity_map, skip_handler, statistics_data) # The analyzer invocation calls __create_timeout as a callback # when the analyzer starts. This callback creates the timeout # watcher over the analyzer process, which in turn returns a # function, that can later be used to check if the analyzer quit # because we killed it due to a timeout. # # We need to capture the "function pointer" returned by # setup_process_timeout as reference, so that we may call it # later. To work around scoping issues, we use a list here so the # "function pointer" is captured by reference. timeout_cleanup = [lambda: False] if analysis_timeout and analysis_timeout > 0: def __create_timeout(analyzer_process): """ Once the analyzer process is started, this method is called. Set up a timeout for the analysis. """ timeout_cleanup[0] = util.setup_process_timeout( analyzer_process, analysis_timeout) else: def __create_timeout(analyzer_process): # If no timeout is given by the client, this callback # shouldn't do anything. pass # Fills up the result handler with the analyzer information. source_analyzer.analyze(analyzer_cmd, rh, analyzer_environment, __create_timeout) # If execution reaches this line, the analyzer process has quit. if timeout_cleanup[0](): LOG.warning("Analyzer ran too long, exceeding time limit " "of {0} seconds.".format(analysis_timeout)) LOG.warning("Considering this analysis as failed...") rh.analyzer_returncode = -1 rh.analyzer_stderr = (">>> CodeChecker: Analysis timed out " "after {0} seconds. <<<\n{1}") \ .format(analysis_timeout, rh.analyzer_stderr) # If source file contains escaped spaces ("\ " tokens), then # clangSA writes the plist file with removing this escape # sequence, whereas clang-tidy does not. We rewrite the file # names to contain no escape sequences for every analyzer. result_file = rh.analyzer_result_file.replace(r'\ ', ' ') result_base = os.path.basename(result_file) ctu_active = is_ctu_active(source_analyzer) ctu_suffix = 'CTU' zip_suffix = ctu_suffix if ctu_active else '' zip_file = result_base + zip_suffix + '.zip' zip_file = os.path.join(failed_dir, zip_file) ctu_zip_file = result_base + ctu_suffix + '.zip' ctu_zip_file = os.path.join(failed_dir, ctu_zip_file) return_codes = rh.analyzer_returncode if rh.analyzer_returncode == 0: # Remove the previously generated error file. if os.path.exists(zip_file): os.remove(zip_file) # Remove the previously generated CTU error file. if os.path.exists(ctu_zip_file): os.remove(ctu_zip_file) handle_success(rh, result_file, result_base, skip_handler, capture_analysis_output, success_dir) LOG.info("[%d/%d] %s analyzed %s successfully." % (progress_checked_num.value, progress_actions.value, action.analyzer_type, source_file_name)) if skip_handler: # We need to check the plist content because skipping # reports in headers can be done only this way. plist_parser.skip_report_from_plist(result_file, skip_handler) else: LOG.error("Analyzing '" + source_file_name + "' with " + action.analyzer_type + " CTU" if ctu_active else " " + "failed.") if not quiet_output_on_stdout: LOG.error('\n' + rh.analyzer_stdout) LOG.error('\n' + rh.analyzer_stderr) handle_failure(source_analyzer, rh, action, zip_file, result_base, actions_map) if ctu_active and ctu_reanalyze_on_failure: LOG.error("Try to reanalyze without CTU") # Try to reanalyze with CTU disabled. source_analyzer, analyzer_cmd, rh, reanalyzed = \ prepare_check(source, action, analyzer_config_map, output_dir, context.severity_map, skip_handler, statistics_data, True) # Fills up the result handler with # the analyzer information. source_analyzer.analyze(analyzer_cmd, rh, analyzer_environment) return_codes = rh.analyzer_returncode if rh.analyzer_returncode == 0: handle_success(rh, result_file, result_base, skip_handler, capture_analysis_output, success_dir, zipfile) msg = "[{0}/{1}] {2} analyzed {3} without" \ " CTU successfully.".format( progress_checked_num.value, progress_actions.value, action.analyzer_type, source_file_name) LOG.info(msg) else: LOG.error("Analyzing '" + source_file_name + "' with " + action.analyzer_type + " without CTU failed.") zip_file = result_base + '.zip' zip_file = os.path.join(failed_dir, zip_file) handle_failure(source_analyzer, rh, action, zip_file, result_base, actions_map) if not quiet_output_on_stdout: if rh.analyzer_returncode: LOG.error('\n' + rh.analyzer_stdout) LOG.error('\n' + rh.analyzer_stderr) else: LOG.debug_analyzer('\n' + rh.analyzer_stdout) LOG.debug_analyzer('\n' + rh.analyzer_stderr) progress_checked_num.value += 1 return return_codes, skipped, reanalyzed, action.analyzer_type, \ result_file, list(action.sources) except Exception as e: LOG.debug_analyzer(str(e)) traceback.print_exc(file=sys.stdout) return 1, skipped, reanalyzed, action.analyzer_type, None, \ list(action.sources)