def initRunBrowserOptions(self): runBrowserOptions = [] if self.options.background: runBrowserOptions.append("--background") if self.dirs.symbolsDir: runBrowserOptions.append("--symbols-dir=" + self.dirs.symbolsDir) if self.options.valgrind: runBrowserOptions.append("--valgrind") suppressions = "" for suppressionsFile in findIgnoreLists.findIgnoreLists(self.knownPath, "valgrind.txt"): suppressions += "--suppressions=" + suppressionsFile + " " vgargs = ( "--error-exitcode=" + str(VALGRIND_ERROR_EXIT_CODE) + " " + "--gen-suppressions=all" + " " + suppressions + "--child-silent-after-fork=yes" + " " + # First part of the workaround for bug 658840 # "--leak-check=full" + " " + # "--show-possibly-lost=no" + " " + "--smc-check=all-non-file" + " " + # "--track-origins=yes" + " " + # "--num-callers=50" + " " + "--quiet" ) runBrowserOptions.append("--vgargs=" + vgargs) # spaces are okay here return runBrowserOptions
def readIgnoreLists(knownPath): global ignoreList global ready ignoreList = [] for filename in findIgnoreLists.findIgnoreLists(knownPath, "crashes.txt"): readIgnoreList(filename) ready = True
def readIgnoreLists(knownPath): global ready for filename in findIgnoreLists.findIgnoreLists(knownPath, "assertions.txt"): readIgnoreList(filename) ready = True print "detect_assertions is ready (ignoring %d strings without filenames and %d strings with filenames)" % ( len(simpleIgnoreList), len(twoPartIgnoreList))
def readIgnoreLists(knownPath): global ready for filename in findIgnoreLists.findIgnoreLists(knownPath, "assertions.txt"): readIgnoreList(filename) ready = True print "detect_assertions is ready (ignoring %d strings without filenames and %d strings with filenames)" % (len(simpleIgnoreList), len(twoPartIgnoreList))
def rdfInit(args): """ Returns (levelAndLines, options). levelAndLines is a function that runs Firefox in a clean profile and analyzes Firefox's output for bugs. """ parser = OptionParser(usage="%prog [options] browserDir [testcaseURL]") parser.add_option("--valgrind", action="store_true", dest="valgrind", default=False, help="use valgrind with a reasonable set of options") parser.add_option("-m", "--minlevel", type="int", dest="minimumInterestingLevel", default=DOM_FINE + 1, help="minimum domfuzz level for lithium to consider the testcase interesting") parser.add_option("--background", action="store_true", dest="background", default=False, help="Run the browser in the background on Mac (e.g. for local reduction)") options, args = parser.parse_args(args) if len(args) < 1: usage("Missing browserDir argument") browserDir = args[0] dirs = FigureOutDirs(getFullPath(browserDir)) # Standalone domInteresting: Optional. Load this URL or file (rather than the Bugzilla front page) # loopdomfuzz: Optional. Test (and possibly splice/reduce) only this URL, rather than looping (but note the prefs file isn't maintained) # Lithium: Required. Reduce this file. options.argURL = args[1] if len(args) > 1 else "" options.browserDir = browserDir # used by loopdomfuzz runBrowserOptions = [] if options.background: runBrowserOptions.append("--background") if dirs.symbolsDir: runBrowserOptions.append("--symbols-dir=" + dirs.symbolsDir) env = os.environ.copy() env['MOZ_FUZZING_SAFE'] = '1' env['REFTEST_FILES_DIR'] = dirs.reftestFilesDir env['ASAN_SYMBOLIZER_PATH'] = os.path.expanduser("~/llvm/build/Release/bin/llvm-symbolizer") if dirs.stackwalk: env['MINIDUMP_STACKWALK'] = dirs.stackwalk runbrowserpy = [sys.executable, "-u", os.path.join(THIS_SCRIPT_DIRECTORY, "runbrowser.py")] knownPath = "mozilla-central" if options.valgrind: runBrowserOptions.append("--valgrind") suppressions = "" for suppressionsFile in findIgnoreLists.findIgnoreLists(knownPath, "valgrind.txt"): suppressions += "--suppressions=" + suppressionsFile + " " vgargs = ( "--error-exitcode=" + str(VALGRIND_ERROR_EXIT_CODE) + " " + "--gen-suppressions=all" + " " + suppressions + "--child-silent-after-fork=yes" + " " + # First part of the workaround for bug 658840 # "--leak-check=full" + " " + # "--show-possibly-lost=no" + " " + "--smc-check=all-non-file" + " " + # "--track-origins=yes" + " " + # "--num-callers=50" + " " + "--quiet" ) runBrowserOptions.append("--vgargs=" + vgargs) # spaces are okay here def levelAndLines(url, logPrefix=None, extraPrefs="", quiet=False, leaveProfile=False): """Run Firefox using the profile created above, detecting bugs and stuff.""" profileDir = mkdtemp(prefix="domfuzz-rdf-profile") createDOMFuzzProfile(profileDir) writePrefs(profileDir, extraPrefs) runBrowserArgs = [dirs.reftestScriptDir, dirs.utilityDir, profileDir] assert logPrefix # :( leakLogFile = logPrefix + "-leaks.txt" runbrowser = subprocess.Popen( runbrowserpy + ["--leak-log-file=" + leakLogFile] + runBrowserOptions + runBrowserArgs + [url], stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, close_fds=close_fds ) alh = AmissLogHandler(knownPath) alh.valgrind = 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 status < 0 and os.name == 'posix': # The program was terminated by a signal, which usually indicates a crash. signum = -status if signum != signal.SIGKILL and signum != signal.SIGTERM and not alh.crashWatcher.crashProcessor: # We did not detect a breakpad/ASan crash in the output, but it looks like the process crashed. # Look for a core file (to feed to gdb) or log from the Mac crash reporter. wantStack = True assert alh.theapp crashLog = sps.grabCrashLog(alh.theapp, alh.pid, logPrefix, wantStack) if crashLog: alh.crashWatcher.readCrashLog(crashLog) else: alh.printAndLog("@@@ The browser crashed, but did not leave behind any crash information!") lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) if alh.newAssertionFailure: lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) if alh.mallocFailure: lev = max(lev, DOM_MALLOC_ERROR) if alh.fuzzerComplained or alh.sawChromeFailure: lev = max(lev, DOM_FUZZER_COMPLAINED) if alh.sawValgrindComplaint: lev = max(lev, DOM_VG_AMISS) if alh.timedOut: if alh.expectedToHang or options.valgrind: alh.printAndLog("%%% An expected hang") else: alh.printAndLog("@@@ Unexpected hang") lev = max(lev, DOM_TIMED_OUT_UNEXPECTEDLY) elif alh.crashWatcher.crashProcessor: if alh.crashWatcher.crashIsKnown: alh.printAndLog("%%% Known crash (from " + alh.crashWatcher.crashProcessor + ")" + alh.crashWatcher.crashSignature) else: alh.printAndLog("@@@ New crash (from " + alh.crashWatcher.crashProcessor + ")" + alh.crashWatcher.crashSignature) lev = max(lev, DOM_NEW_ASSERT_OR_CRASH) elif options.valgrind and status == VALGRIND_ERROR_EXIT_CODE: # Disabled due to leaks in the glxtest process that Firefox forks on Linux. # (Second part of the workaround for bug 658840.) # (We detect Valgrind warnings as they happen, instead.) #alh.printAndLog("@@@ Valgrind complained via exit code") #lev = max(lev, DOM_VG_AMISS) pass elif status < 0 and os.name == 'posix': 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 (OOM or plugin crash?)") elif status == -2147483645 and sps.isWin: alh.printAndLog("%%% Exited with status -2147483645 (plugin issue, bug 867263?)") elif status != 0 and not (sps.isWin and alh.sawFatalAssertion): alh.printAndLog("@@@ Abnormal exit (status %d)" % status) lev = max(lev, DOM_ABNORMAL_EXIT) 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 os.path.exists(leakLogFile) and status == 0 and detect_leaks.amiss(knownPath, leakLogFile, verbose=not quiet) and not alh.expectedToLeak: alh.printAndLog("@@@ Unexpected leak or leak pattern") alh.printAndLog("Leak details: " + os.path.basename(leakLogFile)) lev = max(lev, DOM_NEW_LEAK) else: if alh.sawOMGLEAK and not alh.expectedToLeak: lev = max(lev, DOM_NEW_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) if (lev > DOM_FINE) and logPrefix: with open(logPrefix + "-output.txt", "w") as outlog: outlog.writelines(alh.fullLogHead) subprocess.call(["gzip", logPrefix + "-output.txt"]) with open(logPrefix + "-summary.txt", "w") as summaryLogFile: summaryLogFile.writelines(alh.summaryLog) if (lev == DOM_FINE) and logPrefix: removeIfExists(logPrefix + "-core.gz") removeIfExists(logPrefix + "-crash.txt") if not leaveProfile: shutil.rmtree(profileDir) print "DOMFUZZ INFO | domInteresting.py | " + str(lev) return (lev, alh.FRClines) return levelAndLines, options # return a closure along with the set of options
def valgrindSuppressions(knownPath): return [ "--suppressions=" + filename for filename in findIgnoreLists.findIgnoreLists( knownPath, "valgrind.txt") ]
def valgrindSuppressions(knownPath): return ["--suppressions=" + filename for filename in findIgnoreLists.findIgnoreLists(knownPath, "valgrind.txt")]