def many_timed_runs(targetTime, wtmpDir, args, collector): options = parseOpts(args) engineFlags = options.engineFlags # engineFlags is overwritten later if --random-flags is set. startTime = time.time() if os.path.isdir(sps.normExpUserPath(options.repo)): regressionTestListFile = sps.normExpUserPath(os.path.join(wtmpDir, "regression-tests.list")) with open(regressionTestListFile, "wb") as f: for fn in inTreeRegressionTests(options.repo): f.write(fn + "\n") regressionTestPrologue = makeRegressionTestPrologue(options.repo, regressionTestListFile) else: regressionTestPrologue = "" fuzzjs = sps.normExpUserPath(os.path.join(wtmpDir, "jsfunfuzz.js")) linkFuzzer(fuzzjs, options.repo, regressionTestPrologue) iteration = 0 while True: if targetTime and time.time() > startTime + targetTime: print "Out of time!" os.remove(fuzzjs) if len(os.listdir(wtmpDir)) == 0: os.rmdir(wtmpDir) break # Construct command needed to loop jsfunfuzz fuzzing. jsInterestingArgs = [] jsInterestingArgs.append('--timeout=' + str(options.timeout)) if options.valgrind: jsInterestingArgs.append('--valgrind') jsInterestingArgs.append(options.knownPath) jsInterestingArgs.append(options.jsEngine) if options.randomFlags: engineFlags = shellFlags.randomFlagSet(options.jsEngine) jsInterestingArgs.extend(engineFlags) jsInterestingArgs.extend(['-e', 'maxRunTime=' + str(options.timeout*(1000/2))]) jsInterestingArgs.extend(['-f', fuzzjs]) jsInterestingOptions = jsInteresting.parseOptions(jsInterestingArgs) iteration += 1 logPrefix = sps.normExpUserPath(os.path.join(wtmpDir, "w" + str(iteration))) res = jsInteresting.ShellResult(jsInterestingOptions, jsInterestingOptions.jsengineWithArgs, logPrefix, False) if res.lev != jsInteresting.JS_FINE: showtail(logPrefix + "-out.txt") showtail(logPrefix + "-err.txt") # splice jsfunfuzz.js with `grep FRC wN-out` filenameToReduce = logPrefix + "-reduced.js" [before, after] = fileManipulation.fuzzSplice(fuzzjs) with open(logPrefix + '-out.txt', 'rb') as f: newfileLines = before + [l.replace('/*FRC*/', '') for l in fileManipulation.linesStartingWith(f, "/*FRC*/")] + after fileManipulation.writeLinesToFile(newfileLines, logPrefix + "-orig.js") fileManipulation.writeLinesToFile(newfileLines, filenameToReduce) # Run Lithium and autobisect (make a reduced testcase and find a regression window) itest = [interestingpy] if options.valgrind: itest.append("--valgrind") itest.append("--minlevel=" + str(res.lev)) itest.append("--timeout=" + str(options.timeout)) itest.append(options.knownPath) (lithResult, lithDetails, autoBisectLog) = pinpoint.pinpoint(itest, logPrefix, options.jsEngine, engineFlags, filenameToReduce, options.repo, options.buildOptionsStr, targetTime, res.lev) # Upload with final output if lithResult == lithOps.LITH_FINISHED: fargs = jsInterestingOptions.jsengineWithArgs[:-1] + [filenameToReduce] retestResult = jsInteresting.ShellResult(jsInterestingOptions, fargs, logPrefix + "-final", False) if retestResult.lev > jsInteresting.JS_FINE: res = retestResult quality = 0 else: quality = 6 else: quality = 10 # ddsize = lithOps.ddsize(filenameToReduce) print "Submitting " + filenameToReduce + " (quality=" + str(quality) + ") at " + sps.dateStr() metadata = {} if autoBisectLog: metadata = {"autoBisectLog": ''.join(autoBisectLog)} collector.submit(res.crashInfo, filenameToReduce, quality, metaData=metadata) print "Submitted " + filenameToReduce else: flagsAreDeterministic = "--dump-bytecode" not in engineFlags and '-D' not in engineFlags if options.useCompareJIT and res.lev == jsInteresting.JS_FINE and \ jsInterestingOptions.shellIsDeterministic and flagsAreDeterministic: linesToCompare = jitCompareLines(logPrefix + '-out.txt', "/*FCM*/") jitcomparefilename = logPrefix + "-cj-in.js" fileManipulation.writeLinesToFile(linesToCompare, jitcomparefilename) anyBug = compareJIT.compareJIT(options.jsEngine, engineFlags, jitcomparefilename, logPrefix + "-cj", options.repo, options.buildOptionsStr, targetTime, jsInterestingOptions) if not anyBug: os.remove(jitcomparefilename) jsInteresting.deleteLogs(logPrefix)
def compareLevel(jsEngine, flags, infilename, logPrefix, options, showDetailedDiffs, quickMode): # options dict must be one we can pass to jsInteresting.ShellResult # we also use it directly for knownPath, timeout, and collector # Return: (lev, crashInfo) or (jsInteresting.JS_FINE, None) combos = shellFlags.basicFlagSets(jsEngine) if quickMode: # Only used during initial fuzzing. Allowed to have false negatives. combos = [combos[0]] if len(flags): combos.append(flags) commands = [[jsEngine] + combo + [infilename] for combo in combos] for i in range(0, len(commands)): prefix = logPrefix + "-r" + str(i) command = commands[i] r = jsInteresting.ShellResult(options, command, prefix, True) oom = jsInteresting.oomed(r.err) r.err = ignoreSomeOfStderr(r.err) if (r.rc == 1 or r.rc == 2) and ( anyLineContains(r.out, '[[script] scriptArgs*]') or anyLineContains(r.err, '[scriptfile] [scriptarg...]')): print "Got usage error from:" print " " + sps.shellify(command) assert i > 0 jsInteresting.deleteLogs(prefix) elif r.lev > jsInteresting.JS_OVERALL_MISMATCH: # would be more efficient to run lithium on one or the other, but meh print infilename + " | " + jsInteresting.summaryString( r.issues + ["compareJIT found a more serious bug"], r.lev, r.runinfo.elapsedtime) with open(logPrefix + "-summary.txt", 'wb') as f: f.write('\n'.join(r.issues + [ sps.shellify(command), "compareJIT found a more serious bug" ]) + '\n') print " " + sps.shellify(command) return (r.lev, r.crashInfo) elif r.lev != jsInteresting.JS_FINE or r.rc != 0: print infilename + " | " + jsInteresting.summaryString( r.issues + [ "compareJIT is not comparing output, because the shell exited strangely" ], r.lev, r.runinfo.elapsedtime) print " " + sps.shellify(command) jsInteresting.deleteLogs(prefix) if i == 0: return (jsInteresting.JS_FINE, None) elif oom: # If the shell or python hit a memory limit, we consider the rest of the computation # "tainted" for the purpose of correctness comparison. message = "compareJIT is not comparing output: OOM" print infilename + " | " + jsInteresting.summaryString( r.issues + [message], r.lev, r.runinfo.elapsedtime) jsInteresting.deleteLogs(prefix) if i == 0: return (jsInteresting.JS_FINE, None) elif i == 0: # Stash output from this run (the first one), so for subsequent runs, we can compare against it. (r0, prefix0) = (r, prefix) else: # Compare the output of this run (r.out) to the output of the first run (r0.out), etc. def fpuOptionDisabledAsmOnOneSide(fpuAsmMsg): fpuOptionDisabledAsm = fpuAsmMsg in r0.err or fpuAsmMsg in r.err fpuOptionDiffers = (("--no-fpu" in commands[0]) != ("--no-fpu" in command)) return fpuOptionDisabledAsm and fpuOptionDiffers def optionDisabledAsmOnOneSide(): asmMsg = "asm.js type error: Disabled by javascript.options.asmjs" optionDisabledAsm = anyLineContains( r0.err, asmMsg) or anyLineContains(r.err, asmMsg) optionDiffers = (("--no-asmjs" in commands[0]) != ("--no-asmjs" in command)) return optionDisabledAsm and optionDiffers mismatchErr = ( r.err != r0.err and # --no-fpu (on debug x86_32 only) turns off asm.js compilation, among other things. # This should only affect asm.js diagnostics on stderr. not fpuOptionDisabledAsmOnOneSide( "asm.js type error: Disabled by lack of floating point support" ) and # And also wasm stuff. See bug 1243031. not fpuOptionDisabledAsmOnOneSide( "WebAssembly is not supported on the current device") and not optionDisabledAsmOnOneSide()) mismatchOut = (r.out != r0.out) if mismatchErr or mismatchOut: # Generate a short summary for stdout and a long summary for a "*-summary.txt" file. rerunCommand = sps.shellify([ '~/funfuzz/js/compareJIT.py', "--flags=" + ' '.join(flags), "--timeout=" + str(options.timeout), options.knownPath, jsEngine, os.path.basename(infilename) ]) (summary, issues) = summarizeMismatch(mismatchErr, mismatchOut, prefix0, prefix) summary = " " + sps.shellify( commands[0]) + "\n " + sps.shellify( command) + "\n\n" + summary with open(logPrefix + "-summary.txt", 'wb') as f: f.write(rerunCommand + "\n\n" + summary) print infilename + " | " + jsInteresting.summaryString( issues, jsInteresting.JS_OVERALL_MISMATCH, r.runinfo.elapsedtime) if quickMode: print rerunCommand if showDetailedDiffs: print summary print "" # Create a crashInfo object with empty stdout, and stderr showing diffs pc = ProgramConfiguration.fromBinary(jsEngine) pc.addProgramArguments(flags) crashInfo = CrashInfo.CrashInfo.fromRawCrashData([], summary, pc) return (jsInteresting.JS_OVERALL_MISMATCH, crashInfo) else: # print "compareJIT: match" jsInteresting.deleteLogs(prefix) # All matched :) jsInteresting.deleteLogs(prefix0) return (jsInteresting.JS_FINE, None)