def main(): logger.info(sps.dateStr()) try: updateRepos() except OSError as e: print 'WARNING: OSError hit:' print e logger.info(sps.dateStr())
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 findBlamedCset(options, repoDir, testRev): print "%s | Bisecting on: %s" % (sps.dateStr(), repoDir) hgPrefix = ['hg', '-R', repoDir] # Resolve names such as "tip", "default", or "52707" to stable hg hash ids, e.g. "9f2641871ce8". realStartRepo = sRepo = hgCmds.getRepoHashAndId( repoDir, repoRev=options.startRepo)[0] realEndRepo = eRepo = hgCmds.getRepoHashAndId(repoDir, repoRev=options.endRepo)[0] sps.vdump("Bisecting in the range " + sRepo + ":" + eRepo) # Refresh source directory (overwrite all local changes) to default tip if required. if options.resetRepoFirst: subprocess.check_call(hgPrefix + ['update', '-C', 'default']) # Throws exit code 255 if purge extension is not enabled in .hgrc: subprocess.check_call(hgPrefix + ['purge', '--all']) # Reset bisect ranges and set skip ranges. sps.captureStdout(hgPrefix + ['bisect', '-r']) if options.skipRevs: sps.captureStdout(hgPrefix + ['bisect', '--skip', options.skipRevs]) labels = {} # Specify `hg bisect` ranges. if options.testInitialRevs: currRev = eRepo # If testInitialRevs mode is set, compile and test the latest rev first. else: labels[sRepo] = ('good', 'assumed start rev is good') labels[eRepo] = ('bad', 'assumed end rev is bad') subprocess.check_call(hgPrefix + ['bisect', '-U', '-g', sRepo]) currRev = hgCmds.getCsetHashFromBisectMsg( fileManipulation.firstLine( sps.captureStdout(hgPrefix + ['bisect', '-U', '-b', eRepo])[0])) iterNum = 1 if options.testInitialRevs: iterNum -= 2 skipCount = 0 blamedRev = None while currRev is not None: startTime = time.time() label = testRev(currRev) labels[currRev] = label if label[0] == 'skip': skipCount += 1 # If we use "skip", we tell hg bisect to do a linear search to get around the skipping. # If the range is large, doing a bisect to find the start and endpoints of compilation # bustage would be faster. 20 total skips being roughly the time that the pair of # bisections would take. if skipCount > 20: print 'Skipped 20 times, stopping autoBisect.' break print label[0] + " (" + label[1] + ") ", if iterNum <= 0: print 'Finished testing the initial boundary revisions...', else: print "Bisecting for the n-th round where n is", iterNum, "and 2^n is", \ str(2**iterNum), "...", (blamedGoodOrBad, blamedRev, currRev, sRepo, eRepo) = \ bisectLabel(hgPrefix, options, label[0], currRev, sRepo, eRepo) if options.testInitialRevs: options.testInitialRevs = False assert currRev is None currRev = sRepo # If options.testInitialRevs is set, test earliest possible rev next. iterNum += 1 endTime = time.time() oneRunTime = endTime - startTime print 'This iteration took %.3f seconds to run.' % oneRunTime if blamedRev is not None: checkBlameParents(repoDir, blamedRev, blamedGoodOrBad, labels, testRev, realStartRepo, realEndRepo) sps.vdump("Resetting bisect") subprocess.check_call(hgPrefix + ['bisect', '-U', '-r']) sps.vdump("Resetting working directory") sps.captureStdout(hgPrefix + ['update', '-C', '-r', 'default'], ignoreStderr=True) hgCmds.destroyPyc(repoDir) print sps.dateStr()
def main(): logger.info(sps.dateStr()) updateRepos() logger.info(sps.dateStr())
def ensureBuild(options): if options.existingBuildDir: # Pre-downloaded treeherder builds (browser only for now) bDir = options.existingBuildDir bType = 'local-build' bSrc = bDir bRev = '' manyTimedRunArgs = [] elif not options.useTreeherderBuilds: if options.testType == "js": # Compiled js shells options.buildOptions = buildOptions.parseShellOptions(options.buildOptions) options.timeout = options.timeout or machineTimeoutDefaults(options) with LockDir(compileShell.getLockDirPath(options.buildOptions.repoDir)): bRev = hgCmds.getRepoHashAndId(options.buildOptions.repoDir)[0] cshell = compileShell.CompiledShell(options.buildOptions, bRev) compileShell.obtainShell(cshell, updateLatestTxt=True) bDir = cshell.getShellCacheDir() # Strip out first 3 chars or else the dir name in fuzzing jobs becomes: # js-js-dbg-opt-64-dm-linux # This is because options.testType gets prepended along with a dash later. bType = buildOptions.computeShellType(options.buildOptions)[3:] bSrc = ( 'Create another shell in shell-cache like this one:\n' + 'python -u %s -b "%s -R %s" -r %s\n\n' % ( os.path.join(path3, 'compileShell.py'), options.buildOptions.buildOptionsStr, options.buildOptions.repoDir, bRev ) + '==============================================\n' + '| Fuzzing %s js shell builds\n' % cshell.getRepoName() + '| DATE: %s\n' % sps.dateStr() + '==============================================\n\n') manyTimedRunArgs = mtrArgsCreation(options, cshell) print 'buildDir is: ' + bDir print 'buildSrc is: ' + bSrc else: # Compiled browser options.buildOptions = buildBrowser.parseOptions(options.buildOptions.split()) bDir = options.buildOptions.objDir bType = platform.system() + "-" + os.path.basename(options.buildOptions.mozconfig) bSrc = repr(hgCmds.getRepoHashAndId(options.buildOptions.repoDir)) bRev = '' manyTimedRunArgs = [] success = buildBrowser.tryCompiling(options.buildOptions) if not success: raise Exception('Building a browser failed.') else: # Treeherder js shells and browser # Download from Treeherder and call it 'build' # FIXME: Put 'build' somewhere nicer, like ~/fuzzbuilds/. Don't re-download a build that's up to date. # FIXME: randomize branch selection, get appropriate builds, use appropriate known dirs bDir = 'build' bType = downloadBuild.defaultBuildType(options.repoName, None, True) bSrc = downloadBuild.downloadLatestBuild(bType, './', getJsShell=(options.testType == 'js')) bRev = '' # These two lines are only used for treeherder js shells: shell = os.path.join(bDir, "dist", "js.exe" if sps.isWin else "js") manyTimedRunArgs = ["--random-flags", str(JS_SHELL_DEFAULT_TIMEOUT), "mozilla-central", shell] return BuildInfo(bDir, bType, bSrc, bRev, manyTimedRunArgs)
def ensureBuild(options): if options.existingBuildDir: # Pre-downloaded treeherder builds (browser only for now) bDir = options.existingBuildDir bType = 'local-build' bSrc = bDir bRev = '' manyTimedRunArgs = [] elif not options.useTreeherderBuilds: if options.testType == "js": # Compiled js shells options.buildOptions = buildOptions.parseShellOptions( options.buildOptions) options.timeout = options.timeout or machineTimeoutDefaults( options) with LockDir( compileShell.getLockDirPath(options.buildOptions.repoDir)): bRev = hgCmds.getRepoHashAndId(options.buildOptions.repoDir)[0] cshell = compileShell.CompiledShell(options.buildOptions, bRev) compileShell.obtainShell(cshell, updateLatestTxt=True) bDir = cshell.getShellCacheDir() # Strip out first 3 chars or else the dir name in fuzzing jobs becomes: # js-js-dbg-opt-64-dm-linux # This is because options.testType gets prepended along with a dash later. bType = buildOptions.computeShellType(options.buildOptions)[3:] bSrc = ( 'Create another shell in shell-cache like this one:\n' + 'python -u %s -b "%s -R %s" -r %s\n\n' % (os.path.join(path3, 'compileShell.py'), options.buildOptions.buildOptionsStr, options.buildOptions.repoDir, bRev) + '==============================================\n' + '| Fuzzing %s js shell builds\n' % cshell.getRepoName() + '| DATE: %s\n' % sps.dateStr() + '==============================================\n\n') manyTimedRunArgs = mtrArgsCreation(options, cshell) print 'buildDir is: ' + bDir print 'buildSrc is: ' + bSrc else: # Compiled browser options.buildOptions = buildBrowser.parseOptions( options.buildOptions.split()) bDir = options.buildOptions.objDir bType = platform.system() + "-" + os.path.basename( options.buildOptions.mozconfig) bSrc = repr(hgCmds.getRepoHashAndId(options.buildOptions.repoDir)) bRev = '' manyTimedRunArgs = [] success = buildBrowser.tryCompiling(options.buildOptions) if not success: raise Exception('Building a browser failed.') else: # Treeherder js shells and browser # Download from Treeherder and call it 'build' # FIXME: Put 'build' somewhere nicer, like ~/fuzzbuilds/. Don't re-download a build that's up to date. # FIXME: randomize branch selection, get appropriate builds, use appropriate known dirs bDir = 'build' bType = downloadBuild.defaultBuildType(options.repoName, None, True) bSrc = downloadBuild.downloadLatestBuild( bType, './', getJsShell=(options.testType == 'js')) bRev = '' # These two lines are only used for treeherder js shells: shell = os.path.join(bDir, "dist", "js.exe" if sps.isWin else "js") manyTimedRunArgs = [ "--random-flags", str(JS_SHELL_DEFAULT_TIMEOUT), "mozilla-central", shell ] return BuildInfo(bDir, bType, bSrc, bRev, manyTimedRunArgs)
def findBlamedCset(options, repoDir, testRev): print sps.dateStr() hgPrefix = ['hg', '-R', repoDir] # Resolve names such as "tip", "default", or "52707" to stable hg hash ids, e.g. "9f2641871ce8". realStartRepo = sRepo = hgCmds.getRepoHashAndId(repoDir, repoRev=options.startRepo)[0] realEndRepo = eRepo = hgCmds.getRepoHashAndId(repoDir, repoRev=options.endRepo)[0] sps.vdump("Bisecting in the range " + sRepo + ":" + eRepo) # Refresh source directory (overwrite all local changes) to default tip if required. if options.resetRepoFirst: subprocess.check_call(hgPrefix + ['update', '-C', 'default']) # Throws exit code 255 if purge extension is not enabled in .hgrc: subprocess.check_call(hgPrefix + ['purge', '--all']) # Reset bisect ranges and set skip ranges. sps.captureStdout(hgPrefix + ['bisect', '-r']) if options.skipRevs: sps.captureStdout(hgPrefix + ['bisect', '--skip', options.skipRevs]) labels = {} # Specify `hg bisect` ranges. if options.testInitialRevs: currRev = eRepo # If testInitialRevs mode is set, compile and test the latest rev first. else: labels[sRepo] = ('good', 'assumed start rev is good') labels[eRepo] = ('bad', 'assumed end rev is bad') subprocess.check_call(hgPrefix + ['bisect', '-U', '-g', sRepo]) currRev = hgCmds.getCsetHashFromBisectMsg(fileManipulation.firstLine( sps.captureStdout(hgPrefix + ['bisect', '-U', '-b', eRepo])[0])) iterNum = 1 if options.testInitialRevs: iterNum -= 2 skipCount = 0 blamedRev = None while currRev is not None: startTime = time.time() label = testRev(currRev) labels[currRev] = label if label[0] == 'skip': skipCount += 1 # If we use "skip", we tell hg bisect to do a linear search to get around the skipping. # If the range is large, doing a bisect to find the start and endpoints of compilation # bustage would be faster. 20 total skips being roughly the time that the pair of # bisections would take. if skipCount > 20: print 'Skipped 20 times, stopping autoBisect.' break print label[0] + " (" + label[1] + ") ", if iterNum <= 0: print 'Finished testing the initial boundary revisions...', else: print "Bisecting for the n-th round where n is", iterNum, "and 2^n is", \ str(2**iterNum), "...", (blamedGoodOrBad, blamedRev, currRev, sRepo, eRepo) = \ bisectLabel(hgPrefix, options, label[0], currRev, sRepo, eRepo) if options.testInitialRevs: options.testInitialRevs = False assert currRev is None currRev = sRepo # If options.testInitialRevs is set, test earliest possible rev next. iterNum += 1 endTime = time.time() oneRunTime = endTime - startTime print 'This iteration took %.3f seconds to run.' % oneRunTime if blamedRev is not None: checkBlameParents(repoDir, blamedRev, blamedGoodOrBad, labels, testRev, realStartRepo, realEndRepo) sps.vdump("Resetting bisect") subprocess.check_call(hgPrefix + ['bisect', '-U', '-r']) sps.vdump("Resetting working directory") sps.captureStdout(hgPrefix + ['update', '-C', '-r', 'default'], ignoreStderr=True) hgCmds.destroyPyc(repoDir) print sps.dateStr()