def pinpoint(itest, logPrefix, jsEngine, engineFlags, infilename, bisectRepo, buildOptionsStr, targetTime, suspiciousLevel): """Run Lithium and autobisect. itest must be an array of the form [module, ...] where module is an interestingness module. The module's "interesting" function must accept [...] + [jsEngine] + engineFlags + infilename (If it's not prepared to accept engineFlags, engineFlags must be empty.) """ lithArgs = itest + [jsEngine] + engineFlags + [infilename] (lithResult, lithDetails) = strategicReduction(logPrefix, infilename, lithArgs, targetTime, suspiciousLevel) print() print( "Done running Lithium on the part in between DDBEGIN and DDEND. To reproduce, run:" ) print( sps.shellify( [sys.executable, "-u", "-m", "lithium", "--strategy=check-only"] + lithArgs)) print() if bisectRepo is not "none" and targetTime >= 3 * 60 * 60 and buildOptionsStr is not None: if platform.uname()[2] == 'XP': print( "Not pinpointing to exact changeset since autoBisect does not work well in WinXP." ) elif testJsShellOrXpcshell(jsEngine) != "xpcshell": autobisectCmd = ([sys.executable, autobisectpy] + ["-b", buildOptionsStr] + ["-p", ' '.join(engineFlags + [infilename])] + ["-i"] + itest) print(sps.shellify(autobisectCmd)) autoBisectLogFilename = logPrefix + "-autobisect.txt" subprocess.call(autobisectCmd, stdout=open(autoBisectLogFilename, "w"), stderr=subprocess.STDOUT) print("Done running autobisect. Log: %s" % autoBisectLogFilename) with open(autoBisectLogFilename, 'rb') as f: lines = f.readlines() autoBisectLog = fileManipulation.truncateMid( lines, 50, ["..."]) else: autoBisectLog = [] return (lithResult, lithDetails, autoBisectLog)
def pinpoint(itest, logPrefix, jsEngine, engineFlags, infilename, bisectRepo, buildOptionsStr, targetTime, suspiciousLevel): """ Run Lithium and autobisect. itest must be an array of the form [module, ...] where module is an interestingness module. The module's "interesting" function must accept [...] + [jsEngine] + engineFlags + infilename (If it's not prepared to accept engineFlags, engineFlags must be empty.) """ lithArgs = itest + [jsEngine] + engineFlags + [infilename] (lithResult, lithDetails) = strategicReduction(logPrefix, infilename, lithArgs, targetTime, suspiciousLevel) print "\nDone running Lithium on the part in between DDBEGIN and DDEND. To reproduce, run:" print sps.shellify([lithiumpy, "--strategy=check-only"] + lithArgs) + '\n' if bisectRepo is not "none" and targetTime >= 3*60*60 and buildOptionsStr is not None: if platform.uname()[2] == 'XP': print 'Not pinpointing to exact changeset since autoBisect does not work well in WinXP.' elif testJsShellOrXpcshell(jsEngine) != "xpcshell": autobisectCmd = ( [sys.executable, autobisectpy] + ["-b", buildOptionsStr] + ["-p", ' '.join(engineFlags + [infilename])] + ["-i"] + itest ) print sps.shellify(autobisectCmd) autoBisectLogFilename = logPrefix + "-autobisect.txt" subprocess.call(autobisectCmd, stdout=open(autoBisectLogFilename, "w"), stderr=subprocess.STDOUT) print "Done running autobisect. Log: " + autoBisectLogFilename with open(autoBisectLogFilename, 'rb') as f: lines = f.readlines() autoBisectLog = fileManipulation.truncateMid(lines, 50, ["..."]) else: autoBisectLog = [] return (lithResult, lithDetails, autoBisectLog)
def __init__(self, cfg, url, logPrefix, extraPrefs="", quiet=False, leaveProfile=False): """Run Firefox once, detect bugs, and determine a 'level' based on the most severe unknown bug.""" profileDir = mkdtemp(prefix="domfuzz-rdf-profile") createDOMFuzzProfile(profileDir) writePrefs(profileDir, extraPrefs) runBrowserArgs = [cfg.dirs.reftestScriptDir, cfg.dirs.utilityDir, profileDir] assert logPrefix # :( leakLogFile = logPrefix + "-leaks.txt" runbrowserpy = [sys.executable, "-u", os.path.join(THIS_SCRIPT_DIRECTORY, "runbrowser.py")] runbrowser = subprocess.Popen( runbrowserpy + ["--leak-log-file=" + leakLogFile] + cfg.runBrowserOptions + runBrowserArgs + [url], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # Hmm, CrashInfo.fromRawCrashData expects them separate, but I like them together... env=cfg.env, close_fds=close_fds ) alh = AmissLogHandler(cfg.knownPath, cfg.options.valgrind) # Bug 718208 if extraPrefs.find("inflation") != -1: alh.expectedToRenderInconsistently = True statusLinePrefix = "RUNBROWSER INFO | runbrowser.py | runApp: exited with status " status = -9000 # NB: not using 'for line in runbrowser.stdout' because that uses a hidden buffer # see http://docs.python.org/library/stdtypes.html#file.next while True: line = runbrowser.stdout.readline() if line != '': line = alh.processLine(line) if not quiet: print line, if line.startswith(statusLinePrefix): status = int(line[len(statusLinePrefix):]) else: break lev = DOM_FINE if alh.mallocFailure: lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) if alh.fuzzerComplained or alh.sawChromeFailure: lev = max(lev, DOM_FUZZER_COMPLAINED) if alh.sawValgrindComplaint: lev = max(lev, DOM_VG_AMISS) if alh.sawNewNonfatalAssertion: lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) # Leak stuff if 'user_pref("layers.use-deprecated-textures", true);' in extraPrefs: # Bug 933569 # Doing the change *here* only works because this is a small leak that shouldn't affect the reads in alh alh.expectedToLeak = True if 'user_pref("gfx.downloadable_fonts.disable_cache", true);' in extraPrefs: # Bug 1258031 # This is a large leak. I don't remember what the comment above is about. alh.expectedToLeak = True if os.path.exists(leakLogFile) and status == 0 and detect_leaks.amiss(cfg.knownPath, leakLogFile, verbose=not quiet) and not alh.expectedToLeak: alh.printAndLog(DOMI_MARKER + "Leak (trace-refcnt)") alh.printAndLog("Leak details: " + os.path.basename(leakLogFile)) lev = max(lev, DOM_UNEXPECTED_LEAK) else: if alh.sawOMGLEAK and not alh.expectedToLeak: lev = max(lev, DOM_UNEXPECTED_LEAK) if leakLogFile: # Remove the main leak log file, plus any plugin-process leak log files for f in glob.glob(leakLogFile + "*"): os.remove(f) # Do various stuff based on how the process exited if alh.timedOut: if alh.expectedToHang or cfg.options.valgrind: alh.printAndLog("%%% An expected hang") else: alh.printAndLog(DOMI_MARKER + "Unexpected hang") lev = max(lev, DOM_UNEXPECTED_HANG) elif status < 0 and os.name == 'posix': signum = -status signame = getSignalName(signum, "unknown signal") print "DOMFUZZ INFO | domInteresting.py | Terminated by signal " + str(signum) + " (" + signame + ")" elif status == 1: alh.printAndLog("%%% Exited with status 1 (crash?)") elif status == -2147483645 and sps.isWin: alh.printAndLog("%%% Exited with status -2147483645 (plugin issue, bug 867263?)") elif status != 0: alh.printAndLog(DOMI_MARKER + "Abnormal exit (status %d)" % status) lev = max(lev, DOM_ABNORMAL_EXIT) # Always look for crash information in stderr. linesWithoutLineBreaks = [s.rstrip() for s in alh.fullLog] linesWithoutLineBreaks = fileManipulation.truncateMid(linesWithoutLineBreaks, 5000, ["..."]) crashInfo = CrashInfo.CrashInfo.fromRawCrashData([], linesWithoutLineBreaks, cfg.pc) # If the program crashed but we didn't find crash info in stderr (breakpad/asan), # poll for a core file (to feed to gdb) or log from the Mac crash reporter. if isinstance(crashInfo, CrashInfo.NoCrashInfo) and status < 0 and os.name == 'posix': signum = -status if signum != signal.SIGKILL and signum != signal.SIGTERM: wantStack = True assert alh.theapp crashLog = sps.grabCrashLog(alh.theapp, alh.pid, logPrefix, wantStack) if crashLog: with open(crashLog) as f: auxCrashData = f.readlines() crashInfo = CrashInfo.CrashInfo.fromRawCrashData([], linesWithoutLineBreaks, cfg.pc, auxCrashData=auxCrashData) else: alh.printAndLog(DOMI_MARKER + "The browser crashed, but did not leave behind any crash information!") lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) createCollector.printCrashInfo(crashInfo) if not isinstance(crashInfo, CrashInfo.NoCrashInfo): lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) match = cfg.collector.search(crashInfo) if match[0] is not None: createCollector.printMatchingSignature(match) lev = DOM_FINE if lev > DOM_FINE: with open(logPrefix + "-output.txt", "w") as outlog: outlog.writelines(alh.fullLog) subprocess.call(["gzip", logPrefix + "-output.txt"]) with open(logPrefix + "-summary.txt", "w") as summaryLogFile: summaryLogFile.writelines(alh.summaryLog) if lev == DOM_FINE: removeIfExists(logPrefix + "-core.gz") removeIfExists(logPrefix + "-crash.txt") if not leaveProfile: shutil.rmtree(profileDir) print "DOMFUZZ INFO | domInteresting.py | " + str(lev) self.level = lev self.lines = alh.fullLog self.crashInfo = crashInfo