def _submit_report(self, report, test_cases): collector = Collector() if not self.force_report: # search for a cached signature match with InterProcessLock(str(Path(grz_tmp()) / "fm_sigcache.lock")): _, cache_metadata = collector.search(report.crash_info) # check if signature has been marked as frequent in FM if cache_metadata is not None and cache_metadata["frequent"]: LOG.info( "Frequent crash matched existing signature: %s", cache_metadata["shortDescription"], ) return None if self._ignored(report): LOG.info("Report is in ignore list") return None if report.is_hang: self.add_extra_metadata("is_hang", True) # dump test cases and the contained files to working directory test_case_meta = [] for test_number, test_case in enumerate(test_cases): test_case_meta.append([test_case.adapter_name, test_case.input_fname]) dump_path = report.path / ("%s-%d" % (report.prefix, test_number)) dump_path.mkdir(exist_ok=True) test_case.dump(dump_path, include_details=True) report.crash_info.configuration.addMetadata( {"grizzly_input": repr(test_case_meta)} ) if test_cases: environ_string = " ".join( "=".join(kv) for kv in test_cases[0].env_vars.items() ) report.crash_info.configuration.addMetadata( {"recorded_envvars": environ_string} ) else: self.quality = Quality.NO_TESTCASE report.crash_info.configuration.addMetadata(self._extra_metadata) # TODO: this should likely move to ffpuppet # grab screen log (used in automation) if getenv("WINDOW") is not None: screen_log = Path.cwd() / ("screenlog.%s" % (getenv("WINDOW"),)) if screen_log.is_file(): target_log = report.path / "screenlog.txt" copyfile(str(screen_log), str(target_log)) Report.tail(target_log, 10240) # limit to last 10K with TemporaryDirectory(prefix="fm-zip", dir=grz_tmp()) as tmp_dir: # add results to a zip file zip_name = Path(tmp_dir) / ("%s.zip" % (report.prefix,)) with ZipFile(zip_name, mode="w", compression=ZIP_DEFLATED) as zip_fp: # add test files for entry in report.path.rglob("*"): if entry.is_file(): zip_fp.write( str(entry), arcname=str(entry.relative_to(report.path)) ) # override tool name if specified if self.tool is not None: collector.tool = self.tool # submit results to the FuzzManager server new_entry = collector.submit( report.crash_info, testCase=zip_name, testCaseQuality=self.quality.value ) LOG.info("Logged %d (%s)", new_entry["id"], self.quality.name) return new_entry["id"]
def _submit_report(self, report, test_cases): # search for a cached signature match and if the signature # is already in the cache and marked as frequent, don't bother submitting with InterProcessLock(pathjoin(grz_tmp(), "fm_sigcache.lock")): collector = Collector() cache_sig_file, cache_metadata = collector.search(report.crash_info) if cache_metadata is not None: if cache_metadata["frequent"]: LOG.info("Frequent crash matched existing signature: %s", cache_metadata["shortDescription"]) if not self.force_report: return elif "bug__id" in cache_metadata: LOG.info("Crash matched existing signature (bug %s): %s", cache_metadata["bug__id"], cache_metadata["shortDescription"]) # we will still report this one, but no more cache_metadata["frequent"] = True # there is already a signature, initialize count cache_metadata.setdefault("_grizzly_seen_count", 0) else: # there is no signature, create one locally so we can count # the number of times we've seen it max_frames = report.crash_signature_max_frames(report.crash_info) cache_sig_file = collector.generate(report.crash_info, numFrames=max_frames) cache_metadata = { "_grizzly_seen_count": 0, "frequent": False, "shortDescription": report.crash_info.createShortSignature()} if cache_sig_file is None: if self._ignored(report): LOG.info("Report is unsupported and is in ignore list") return LOG.warning("Report is unsupported by FM, saved to %r", report.path) # TODO: we should check if stackhasher failed too raise RuntimeError("Failed to create FM signature") # limit the number of times we report per cycle cache_metadata["_grizzly_seen_count"] += 1 if cache_metadata["_grizzly_seen_count"] >= self.MAX_REPORTS: # we will still report this one, but no more cache_metadata["frequent"] = True metadata_file = cache_sig_file.replace(".signature", ".metadata") with open(metadata_file, "w") as meta_fp: dump(cache_metadata, meta_fp) # dump test cases and the contained files to working directory test_case_meta = [] for test_number, test_case in enumerate(test_cases): test_case_meta.append([test_case.adapter_name, test_case.input_fname]) dump_path = pathjoin(report.path, "%s-%d" % (report.prefix, test_number)) if not isdir(dump_path): mkdir(dump_path) test_case.dump(dump_path, include_details=True) report.crash_info.configuration.addMetadata({"grizzly_input": repr(test_case_meta)}) if test_cases: environ_string = " ".join("=".join(kv) for kv in test_cases[0].env_vars.items()) report.crash_info.configuration.addMetadata({"recorded_envvars": environ_string}) else: self.quality = self.QUAL_NO_TESTCASE report.crash_info.configuration.addMetadata(self._extra_metadata) # grab screen log (used in automation) if getenv("WINDOW") is not None: screen_log = pathjoin(getcwd(), ".".join(["screenlog", getenv("WINDOW")])) if isfile(screen_log): target_log = pathjoin(report.path, "screenlog.txt") copyfile(screen_log, target_log) Report.tail(target_log, 10240) # limit to last 10K # add results to a zip file zip_name = "%s.zip" % (report.prefix,) with ZipFile(zip_name, mode="w", compression=ZIP_DEFLATED) as zip_fp: # add test files for dir_name, _, dir_files in walk(report.path): arc_path = relpath(dir_name, report.path) for file_name in dir_files: zip_fp.write( pathjoin(dir_name, file_name), arcname=pathjoin(arc_path, file_name)) # override tool name if specified if self.tool is not None: collector.tool = self.tool # announce shortDescription if crash is not in a bucket if cache_metadata["_grizzly_seen_count"] == 1 and not cache_metadata["frequent"]: LOG.info("Submitting new crash %r", cache_metadata["shortDescription"]) # submit results to the FuzzManager server new_entry = collector.submit(report.crash_info, testCase=zip_name, testCaseQuality=self.quality) LOG.info("Logged %d with quality %d", new_entry["id"], self.quality) # remove zipfile if isfile(zip_name): unlink(zip_name)