コード例 #1
0
def createReproFile(fuzzerJS, extraPrefs, lines, logPrefix):
    contentTypes = linesStartingWith(lines, "FRCX Content type: ")
    contentType = afterColon(
        contentTypes[0]) if len(contentTypes) > 0 else "text/html"

    extDict = {
        'text/html': 'html',
        'application/xhtml+xml': 'xhtml',
        'image/svg+xml': 'svg',
        'application/vnd.mozilla.xul+xml': 'xul',
        # 'text/xml' is tricky.  We'd want to know the xmlns of the root, and steal its contents but use .xml.
        # But treating it as xhtml is better than doing nothing, for now.
        'text/xml': 'xhtml'
    }

    if contentType in extDict:
        extension = extDict[contentType]
    else:
        print "loopdomfuzz is not sure what to do with content type " + repr(
            contentType) + " :("
        extension = "xhtml"

    [wbefore, wafter] = fuzzDice(os.path.join(emptiesDir, "a." + extension))

    possibleDoctype = []
    if contentType == "text/html":
        docTypes = linesStartingWith(lines, "FRCX Doctype: ")
        if len(docTypes) > 0:
            possibleDoctype = [afterColon(docTypes[0]) + "\n"]

    [jbefore, jafter] = fuzzSplice(fuzzerJS)
    fuzzlines = [
        line[12:] for line in linesStartingWith(lines, "  /*FRCA1*/ ")
    ]
    if len(fuzzlines) < 3:
        fuzzlines = [
            "// Startup crash?\n", "var fuzzSettings = [42,0,42,42,3000,0];\n",
            "var fuzzCommands = [];\n", "// DDBEGIN\n"
        ]
    quittage = [
        extraPrefs,
        "// DDEND\n",
        'fuzzCommands.push({ note: "done", rest: true, timeout: 3000});\n',
        'fuzzCommands.push({ note: "quit", fun: function() { fuzzPriv.quitApplication(); } });\n',
        "\n",
        "function user_pref() { /* Allow randomPrefs.py to parse user_pref lines from this file */ }\n",
    ]
    linesToWrite = possibleDoctype + wbefore + jbefore + fuzzlines + quittage + jafter + wafter

    oFN = logPrefix + "-splice-orig." + extension
    rFN = logPrefix + "-splice-reduced." + extension
    writeLinesToFile(linesToWrite, oFN)
    writeLinesToFile(linesToWrite, rFN)
    subprocess.call(["gzip", oFN])

    return rFN
コード例 #2
0
ファイル: loopdomfuzz.py プロジェクト: shuixi2013/funfuzz
def createReproFile(fuzzerJS, extraPrefs, lines, logPrefix):
    contentTypes = linesStartingWith(lines, "FRCX Content type: ")
    contentType = afterColon(contentTypes[0]) if len(contentTypes) > 0 else "text/html"

    extDict = {
        "text/html": "html",
        "application/xhtml+xml": "xhtml",
        "image/svg+xml": "svg",
        "application/vnd.mozilla.xul+xml": "xul",
        # 'text/xml' is tricky.  We'd want to know the xmlns of the root, and steal its contents but use .xml.
        # But treating it as xhtml is better than doing nothing, for now.
        "text/xml": "xhtml",
    }

    if contentType in extDict:
        extension = extDict[contentType]
    else:
        print "loopdomfuzz is not sure what to do with content type " + repr(contentType) + " :("
        extension = "xhtml"

    [wbefore, wafter] = fuzzDice(os.path.join(emptiesDir, "a." + extension))

    possibleDoctype = []
    if contentType == "text/html":
        docTypes = linesStartingWith(lines, "FRCX Doctype: ")
        if len(docTypes) > 0:
            possibleDoctype = [afterColon(docTypes[0]) + "\n"]

    [jbefore, jafter] = fuzzSplice(fuzzerJS)
    fuzzlines = [line[12:] for line in linesStartingWith(lines, "  /*FRCA1*/ ")]
    if len(fuzzlines) < 3:
        fuzzlines = [
            "// Startup crash?\n",
            "var fuzzSettings = [42,0,42,42,3000,0];\n",
            "var fuzzCommands = [];\n",
            "// DDBEGIN\n",
        ]
    quittage = [
        extraPrefs,
        "// DDEND\n",
        'fuzzCommands.push({ note: "done", rest: true, timeout: 3000});\n',
        'fuzzCommands.push({ note: "quit", fun: function() { fuzzPriv.quitApplication(); } });\n',
        "\n",
        "function user_pref() { /* Allow randomPrefs.py to parse user_pref lines from this file */ }\n",
    ]
    linesToWrite = possibleDoctype + wbefore + jbefore + fuzzlines + quittage + jafter + wafter

    oFN = logPrefix + "-splice-orig." + extension
    rFN = logPrefix + "-splice-reduced." + extension
    writeLinesToFile(linesToWrite, oFN)
    writeLinesToFile(linesToWrite, rFN)
    subprocess.call(["gzip", oFN])

    return rFN
コード例 #3
0
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)
コード例 #4
0
def strategicReduction(logPrefix, infilename, lithArgs, targetTime, lev):
    '''Reduce jsfunfuzz output files using Lithium by using various strategies.'''
    reductionCount = [
        0
    ]  # This is an array because Python does not like assigning to upvars.
    backupFilename = infilename + '-backup'

    def lithReduceCmd(strategy):
        '''Lithium reduction commands accepting various strategies.'''
        reductionCount[0] += 1
        fullLithArgs = [x for x in (strategy + lithArgs)
                        if x]  # Remove empty elements
        print sps.shellify([lithiumpy] + fullLithArgs)

        desc = '-chars' if strategy == '--char' else '-lines'
        (lithResult, lithDetails) = runLithium(
            fullLithArgs, logPrefix + "-" + str(reductionCount[0]) + desc,
            targetTime)
        if lithResult == LITH_FINISHED:
            shutil.copy2(infilename, backupFilename)

        return lithResult, lithDetails

    print '\nRunning the first line reduction...\n'
    # Step 1: Run the first instance of line reduction.
    lithResult, lithDetails = lithReduceCmd([])

    if lithDetails is not None:  # lithDetails can be None if testcase no longer becomes interesting
        origNumOfLines = int(lithDetails.split()[0])

    hasTryItOut = False
    hasTryItOutRegex = re.compile('count=[0-9]+; tryItOut\("')

    with open(infilename, 'rb') as f:
        for line in linesWith(f, '; tryItOut("'):
            # Checks if testcase came from jsfunfuzz or compareJIT.
            hasTryItOut = hasTryItOutRegex.match(line)
            if hasTryItOut:  # Stop searching after finding the first tryItOut line.
                break

    # Step 2: Run 1 instance of 1-line reduction after moving tryItOut and count=X around.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:

        tryItOutAndCountRegex = re.compile('"\);\ncount=([0-9]+); tryItOut\("',
                                           re.MULTILINE)
        with open(infilename, 'rb') as f:
            infileContents = f.read()
            infileContents = re.sub(tryItOutAndCountRegex,
                                    ';\\\n"); count=\\1; tryItOut("\\\n',
                                    infileContents)
        with open(infilename, 'wb') as f:
            f.write(infileContents)

        print '\nRunning 1 instance of 1-line reduction after moving tryItOut and count=X...\n'
        # --chunksize=1: Reduce only individual lines, for only 1 round.
        lithResult, lithDetails = lithReduceCmd(['--chunksize=1'])

    # Step 3: Run 1 instance of 2-line reduction after moving count=X to its own line and add a
    # 1-line offset.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        intendedLines = []
        with open(infilename, 'rb') as f:
            for line in f.readlines(
            ):  # The testcase is likely to already be partially reduced.
                if 'dumpln(cookie' not in line:  # jsfunfuzz-specific line ignore
                    # This should be simpler than re.compile.
                    intendedLines.append(
                        line.replace('; count=', ';\ncount=').replace(
                            '; tryItOut("', ';\ntryItOut("')
                        # The 1-line offset is added here.
                        .replace('SPLICE DDBEGIN', 'SPLICE DDBEGIN\n'))

        writeLinesToFile(intendedLines, infilename)
        print '\nRunning 1 instance of 2-line reduction after moving count=X to its own line...\n'
        lithResult, lithDetails = lithReduceCmd(['--chunksize=2'])

    # Step 4: Run 1 instance of 2-line reduction again, e.g. to remove pairs of STRICT_MODE lines.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        print '\nRunning 1 instance of 2-line reduction again...\n'
        lithResult, lithDetails = lithReduceCmd(['--chunksize=2'])

    isLevOverallMismatchAsmJsAvailable = (lev == JS_OVERALL_MISMATCH) and \
        fileContainsStr(infilename, 'isAsmJSCompilationAvailable')
    # Step 5 (not always run): Run character reduction within interesting lines.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and targetTime is None and \
            lev >= JS_OVERALL_MISMATCH and not isLevOverallMismatchAsmJsAvailable:
        print '\nRunning character reduction...\n'
        lithResult, lithDetails = lithReduceCmd(['--char'])

    # Step 6: Run line reduction after activating SECOND DDBEGIN with a 1-line offset.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        infileContents = []
        with open(infilename, 'rb') as f:
            for line in f.readlines():
                if 'NIGEBDD' in line:
                    infileContents.append(line.replace('NIGEBDD', 'DDBEGIN'))
                    infileContents.append(
                        '\n')  # The 1-line offset is added here.
                    continue
                infileContents.append(line)
        with open(infilename, 'wb') as f:
            f.writelines(infileContents)

        print '\nRunning line reduction with a 1-line offset...\n'
        lithResult, lithDetails = lithReduceCmd([])

    # Step 7: Run line reduction for a final time.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        print '\nRunning the final line reduction...\n'
        lithResult, lithDetails = lithReduceCmd([])

    # Restore from backup if testcase can no longer be reproduced halfway through reduction.
    if lithResult != LITH_FINISHED and lithResult != LITH_PLEASE_CONTINUE:
        # Probably can move instead of copy the backup, once this has stabilised.
        if os.path.isfile(backupFilename):
            shutil.copy2(backupFilename, infilename)
        else:
            print 'DEBUG! backupFilename is supposed to be: ' + backupFilename

    return lithResult, lithDetails
コード例 #5
0
ファイル: pinpoint.py プロジェクト: nth10sd/funfuzz
def strategicReduction(logPrefix, infilename, lithArgs, targetTime, lev):
    """Reduce jsfunfuzz output files using Lithium by using various strategies."""
    reductionCount = [0]  # This is an array because Python does not like assigning to upvars.
    backupFilename = infilename + '-backup'

    def lithReduceCmd(strategy):
        """Lithium reduction commands accepting various strategies."""
        reductionCount[0] += 1
        fullLithArgs = [x for x in (strategy + lithArgs) if x]  # Remove empty elements
        print sps.shellify([lithiumpy] + fullLithArgs)

        desc = '-chars' if strategy == '--char' else '-lines'
        (lithResult, lithDetails) = runLithium(fullLithArgs, logPrefix + "-" +
                                               str(reductionCount[0]) + desc, targetTime)
        if lithResult == LITH_FINISHED:
            shutil.copy2(infilename, backupFilename)

        return lithResult, lithDetails

    print '\nRunning the first line reduction...\n'
    # Step 1: Run the first instance of line reduction.
    lithResult, lithDetails = lithReduceCmd([])

    if lithDetails is not None:  # lithDetails can be None if testcase no longer becomes interesting
        origNumOfLines = int(lithDetails.split()[0])

    hasTryItOut = False
    hasTryItOutRegex = re.compile(r'count=[0-9]+; tryItOut\("')

    with open(infilename, 'rb') as f:
        for line in fileManipulation.linesWith(f, '; tryItOut("'):
            # Checks if testcase came from jsfunfuzz or compareJIT.
            # Do not use .match here, it only matches from the start of the line:
            # https://docs.python.org/2/library/re.html#search-vs-match
            hasTryItOut = hasTryItOutRegex.search(line)
            if hasTryItOut:  # Stop searching after finding the first tryItOut line.
                break

    # Step 2: Run 1 instance of 1-line reduction after moving tryItOut and count=X around.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:

        tryItOutAndCountRegex = re.compile(r'"\);\ncount=([0-9]+); tryItOut\("', re.MULTILINE)
        with open(infilename, 'rb') as f:
            infileContents = f.read()
            infileContents = re.sub(tryItOutAndCountRegex, ';\\\n"); count=\\1; tryItOut("\\\n',
                                    infileContents)
        with open(infilename, 'wb') as f:
            f.write(infileContents)

        print '\nRunning 1 instance of 1-line reduction after moving tryItOut and count=X...\n'
        # --chunksize=1: Reduce only individual lines, for only 1 round.
        lithResult, lithDetails = lithReduceCmd(['--chunksize=1'])

    # Step 3: Run 1 instance of 2-line reduction after moving count=X to its own line and add a
    # 1-line offset.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        intendedLines = []
        with open(infilename, 'rb') as f:
            for line in f:  # The testcase is likely to already be partially reduced.
                if 'dumpln(cookie' not in line:  # jsfunfuzz-specific line ignore
                    # This should be simpler than re.compile.
                    intendedLines.append(line.replace('; count=', ';\ncount=')
                                         .replace('; tryItOut("', ';\ntryItOut("')
                                         # The 1-line offset is added here.
                                         .replace('SPLICE DDBEGIN', 'SPLICE DDBEGIN\n'))

        fileManipulation.writeLinesToFile(intendedLines, infilename)
        print '\nRunning 1 instance of 2-line reduction after moving count=X to its own line...\n'
        lithResult, lithDetails = lithReduceCmd(['--chunksize=2'])

    # Step 4: Run 1 instance of 2-line reduction again, e.g. to remove pairs of STRICT_MODE lines.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        print '\nRunning 1 instance of 2-line reduction again...\n'
        lithResult, lithDetails = lithReduceCmd(['--chunksize=2'])

    isLevOverallMismatchAsmJsAvailable = (lev == JS_OVERALL_MISMATCH) and \
        fileContainsStr(infilename, 'isAsmJSCompilationAvailable')
    # Step 5 (not always run): Run character reduction within interesting lines.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and targetTime is None and \
            lev >= JS_OVERALL_MISMATCH and not isLevOverallMismatchAsmJsAvailable:
        print '\nRunning character reduction...\n'
        lithResult, lithDetails = lithReduceCmd(['--char'])

    # Step 6: Run line reduction after activating SECOND DDBEGIN with a 1-line offset.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        infileContents = []
        with open(infilename, 'rb') as f:
            for line in f:
                if 'NIGEBDD' in line:
                    infileContents.append(line.replace('NIGEBDD', 'DDBEGIN'))
                    infileContents.append('\n')  # The 1-line offset is added here.
                    continue
                infileContents.append(line)
        with open(infilename, 'wb') as f:
            f.writelines(infileContents)

        print '\nRunning line reduction with a 1-line offset...\n'
        lithResult, lithDetails = lithReduceCmd([])

    # Step 7: Run line reduction for a final time.
    if lithResult == LITH_FINISHED and origNumOfLines <= 50 and hasTryItOut and lev >= JS_VG_AMISS:
        print '\nRunning the final line reduction...\n'
        lithResult, lithDetails = lithReduceCmd([])

    # Restore from backup if testcase can no longer be reproduced halfway through reduction.
    if lithResult != LITH_FINISHED and lithResult != LITH_PLEASE_CONTINUE:
        # Probably can move instead of copy the backup, once this has stabilised.
        if os.path.isfile(backupFilename):
            shutil.copy2(backupFilename, infilename)
        else:
            print 'DEBUG! backupFilename is supposed to be: ' + backupFilename

    return lithResult, lithDetails
コード例 #6
0
    def __init__(self, options, runthis, logPrefix, inCompareJIT):
        pathToBinary = runthis[0]
        # This relies on the shell being a local one from compileShell.py:
        # Ignore trailing ".exe" in Win, also abspath makes it work w/relative paths like './js'
        pc = ProgramConfiguration.fromBinary(
            os.path.abspath(pathToBinary).split('.')[0])
        pc.addProgramArguments(runthis[1:-1])

        if options.valgrind:
            runthis = (inspectShell.constructVgCmdList(
                errorCode=VALGRIND_ERROR_EXIT_CODE) +
                       valgrindSuppressions(options.knownPath) + runthis)

        preexec_fn = ulimitSet if os.name == 'posix' else None
        runinfo = timed_run.timed_run(runthis,
                                      options.timeout,
                                      logPrefix,
                                      preexec_fn=preexec_fn)

        lev = JS_FINE
        issues = []
        auxCrashData = []

        # FuzzManager expects a list of strings rather than an iterable, so bite the
        # bullet and 'readlines' everything into memory.
        with open(logPrefix + "-out.txt") as f:
            out = f.readlines()
        with open(logPrefix + "-err.txt") as f:
            err = f.readlines()

        if options.valgrind and runinfo.return_code == VALGRIND_ERROR_EXIT_CODE:
            issues.append("valgrind reported an error")
            lev = max(lev, JS_VG_AMISS)
            valgrindErrorPrefix = "==" + str(runinfo.pid) + "=="
            for line in err:
                if valgrindErrorPrefix and line.startswith(
                        valgrindErrorPrefix):
                    issues.append(line.rstrip())
        elif runinfo.sta == timed_run.CRASHED:
            if sps.grabCrashLog(runthis[0], runinfo.pid, logPrefix, True):
                with open(logPrefix + "-crash.txt") as f:
                    auxCrashData = [line.strip() for line in f.readlines()]
        elif detect_malloc_errors.amiss(logPrefix):
            issues.append("malloc error")
            lev = max(lev, JS_NEW_ASSERT_OR_CRASH)
        elif runinfo.return_code == 0 and not inCompareJIT:
            # We might have(??) run jsfunfuzz directly, so check for special kinds of bugs
            for line in out:
                if line.startswith("Found a bug: ") and not ("NestTest" in line
                                                             and oomed(err)):
                    lev = JS_DECIDED_TO_EXIT
                    issues.append(line.rstrip())
            if options.shellIsDeterministic and not understoodJsfunfuzzExit(
                    out, err) and not oomed(err):
                issues.append("jsfunfuzz didn't finish")
                lev = JS_DID_NOT_FINISH

        # Copy non-crash issues to where FuzzManager's "AssertionHelper.py" can see it.
        if lev != JS_FINE:
            for issue in issues:
                err.append("[Non-crash bug] " + issue)

        # Finally, make a CrashInfo object and parse stack traces for asan/crash/assertion bugs
        crashInfo = CrashInfo.CrashInfo.fromRawCrashData(
            out, err, pc, auxCrashData=auxCrashData)

        createCollector.printCrashInfo(crashInfo)
        # We only care about crashes and assertion failures on shells with no symbols
        # Note that looking out for the Assertion failure message is highly SpiderMonkey-specific
        if not isinstance(crashInfo, CrashInfo.NoCrashInfo) or \
                'Assertion failure: ' in str(crashInfo.rawStderr) or \
                'Segmentation fault' in str(crashInfo.rawStderr) or \
                'Bus error' in str(crashInfo.rawStderr):
            lev = max(lev, JS_NEW_ASSERT_OR_CRASH)

        match = options.collector.search(crashInfo)
        if match[0] is not None:
            createCollector.printMatchingSignature(match)
            lev = JS_FINE

        print("%s | %s" %
              (logPrefix, summaryString(issues, lev, runinfo.elapsedtime)))

        if lev != JS_FINE:
            fileManipulation.writeLinesToFile([
                'Number: ' + logPrefix + '\n',
                'Command: ' + sps.shellify(runthis) + '\n'
            ] + ['Status: ' + i + "\n" for i in issues],
                                              logPrefix + '-summary.txt')

        self.lev = lev
        self.out = out
        self.err = err
        self.issues = issues
        self.crashInfo = crashInfo
        self.match = match
        self.runinfo = runinfo
        self.return_code = runinfo.return_code
コード例 #7
0
ファイル: loopjsfunfuzz.py プロジェクト: ufwt/funfuzz
def many_timed_runs(targetTime, wtmpDir, args):
    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)
            return (lithOps.HAPPY, None)

        # 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])
        jsunhappyOptions = jsInteresting.parseOptions(jsInterestingArgs)

        iteration += 1
        logPrefix = sps.normExpUserPath(
            os.path.join(wtmpDir, "w" + str(iteration)))

        level = jsInteresting.jsfunfuzzLevel(jsunhappyOptions, logPrefix)

        if level != 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(level))
            itest.append("--timeout=" + str(options.timeout))
            itest.append(options.knownPath)
            (lithResult, lithDetails) = pinpoint.pinpoint(
                itest, logPrefix, options.jsEngine, engineFlags,
                filenameToReduce, options.repo, options.buildOptionsStr,
                targetTime, level)
            if targetTime:
                return (lithResult, lithDetails)

        else:
            shellIsDeterministic = inspectShell.queryBuildConfiguration(
                options.jsEngine, 'more-deterministic')
            flagsAreDeterministic = "--dump-bytecode" not in engineFlags and '-D' not in engineFlags
            if options.useCompareJIT and level == jsInteresting.JS_FINE and \
                    shellIsDeterministic and flagsAreDeterministic:
                linesToCompare = jitCompareLines(logPrefix + '-out.txt',
                                                 "/*FCM*/")
                jitcomparefilename = logPrefix + "-cj-in.js"
                fileManipulation.writeLinesToFile(linesToCompare,
                                                  jitcomparefilename)
                (lithResult, lithDetails) = compareJIT.compareJIT(
                    options.jsEngine, engineFlags, jitcomparefilename,
                    logPrefix + "-cj", options.knownPath, options.repo,
                    options.buildOptionsStr, options.timeout, targetTime)
                if lithResult == lithOps.HAPPY:
                    os.remove(jitcomparefilename)
                if targetTime and lithResult != lithOps.HAPPY:
                    jsInteresting.deleteLogs(logPrefix)
                    return (lithResult, lithDetails)
            jsInteresting.deleteLogs(logPrefix)
コード例 #8
0
    def __init__(self, options, runthis, logPrefix, inCompareJIT):
        pathToBinary = runthis[0]
        # This relies on the shell being a local one from compileShell.py:
        pc = ProgramConfiguration.fromBinary(pathToBinary.split('.')[0])  # Ignore trailing ".exe" in Win
        pc.addProgramArguments(runthis[1:-1])

        if options.valgrind:
            runthis = (
                inspectShell.constructVgCmdList(errorCode=VALGRIND_ERROR_EXIT_CODE) +
                valgrindSuppressions(options.knownPath) +
                runthis)

        preexec_fn = ulimitSet if os.name == 'posix' else None
        runinfo = timedRun.timed_run(runthis, options.timeout, logPrefix, preexec_fn=preexec_fn)

        lev = JS_FINE
        issues = []
        auxCrashData = []

        # FuzzManager expects a list of strings rather than an iterable, so bite the
        # bullet and 'readlines' everything into memory.
        with open(logPrefix + "-out.txt") as f:
            out = f.readlines()
        with open(logPrefix + "-err.txt") as f:
            err = f.readlines()

        if options.valgrind and runinfo.rc == VALGRIND_ERROR_EXIT_CODE:
            issues.append("valgrind reported an error")
            lev = max(lev, JS_VG_AMISS)
            valgrindErrorPrefix = "==" + str(runinfo.pid) + "=="
            for line in err:
                if valgrindErrorPrefix and line.startswith(valgrindErrorPrefix):
                    issues.append(line.rstrip())
        elif runinfo.sta == timedRun.CRASHED:
            if sps.grabCrashLog(runthis[0], runinfo.pid, logPrefix, True):
                with open(logPrefix + "-crash.txt") as f:
                    auxCrashData = [line.strip() for line in f.readlines()]
        elif detect_malloc_errors.amiss(logPrefix):
            issues.append("malloc error")
            lev = max(lev, JS_NEW_ASSERT_OR_CRASH)
        elif runinfo.rc == 0 and not inCompareJIT:
            # We might have(??) run jsfunfuzz directly, so check for special kinds of bugs
            for line in out:
                if line.startswith("Found a bug: ") and not ("NestTest" in line and oomed(err)):
                    lev = JS_DECIDED_TO_EXIT
                    issues.append(line.rstrip())
            if options.shellIsDeterministic and not understoodJsfunfuzzExit(out, err) and not oomed(err):
                issues.append("jsfunfuzz didn't finish")
                lev = JS_DID_NOT_FINISH

        # Copy non-crash issues to where FuzzManager's "AssertionHelper.py" can see it.
        if lev != JS_FINE:
            for issue in issues:
                err.append("[Non-crash bug] " + issue)

        # Finally, make a CrashInfo object and parse stack traces for asan/crash/assertion bugs
        crashInfo = CrashInfo.CrashInfo.fromRawCrashData(out, err, pc, auxCrashData=auxCrashData)

        createCollector.printCrashInfo(crashInfo)
        if not isinstance(crashInfo, CrashInfo.NoCrashInfo):
            lev = max(lev, JS_NEW_ASSERT_OR_CRASH)

        match = options.collector.search(crashInfo)
        if match[0] is not None:
            createCollector.printMatchingSignature(match)
            lev = JS_FINE

        print logPrefix + " | " + summaryString(issues, lev, runinfo.elapsedtime)

        if lev != JS_FINE:
            fileManipulation.writeLinesToFile(
                ['Number: ' + logPrefix + '\n',
                 'Command: ' + sps.shellify(runthis) + '\n'] +
                ['Status: ' + i + "\n" for i in issues],
                logPrefix + '-summary.txt')

        self.lev = lev
        self.out = out
        self.err = err
        self.issues = issues
        self.crashInfo = crashInfo
        self.match = match
        self.runinfo = runinfo
        self.rc = runinfo.rc
コード例 #9
0
ファイル: jsInteresting.py プロジェクト: shuixi2013/funfuzz
def jsfunfuzzLevel(options, logPrefix, quiet=False):
    (lev, issues, runinfo) = baseLevel(
        options.jsengineWithArgs, options.timeout, options.knownPath, logPrefix, valgrind=options.valgrind
    )

    if lev == JS_FINE:
        # Check for unexplained exits and for jsfunfuzz saying "Found a bug".
        understoodExit = False

        # Read in binary mode, because otherwise Python on Windows will
        # throw a fit when it encounters certain unicode.  Note that this
        # makes line endings platform-specific.

        if "-dm-" in options.jsengineWithArgs[0]:
            # Since this is an --enable-more-deterministic build, we should get messages on stderr
            # if the shell quit() or terminate() functions are called.
            # (We use a sketchy filename-matching check because it's faster than inspecting the binary.)
            with open(logPrefix + "-err.txt", "rb") as f:
                for line in f:
                    if "terminate called" in line or "quit called" in line:
                        understoodExit = True
                    if "can't allocate region" in line:
                        understoodExit = True
        else:
            understoodExit = True

        with open(logPrefix + "-out.txt", "rb") as f:
            for line in f:
                if line.startswith("It's looking good!") or line.startswith(
                    "jsfunfuzz broke its own scripting environment: "
                ):
                    understoodExit = True
                if line.startswith("Found a bug: "):
                    understoodExit = True
                    if not ("NestTest" in line and oomed(logPrefix)):
                        lev = JS_DECIDED_TO_EXIT
                        issues.append(line.rstrip())
                        # FIXME: if not quiet:
                        # FIXME:     output everything between this line and "jsfunfuzz stopping due to finding a bug."

        if not understoodExit:
            issues.append("jsfunfuzz didn't finish")
            lev = JS_DID_NOT_FINISH

    # FIXME: if not quiet:
    # FIXME:     output the last tryItOut line

    if lev <= JS_ABNORMAL_EXIT:  # JS_ABNORMAL_EXIT and below (inclusive) will be ignored.
        sps.vdump("jsfunfuzzLevel is ignoring a baseLevel of " + str(lev))
        lev = JS_FINE
        issues = []

    if lev != JS_FINE:
        # FIXME: compareJIT failures do not generate this -summary file.
        statusIssueList = []
        for i in issues:
            statusIssueList.append("Status: " + i)
        assert len(statusIssueList) != 0
        fileManipulation.writeLinesToFile(
            ["Number: " + logPrefix + "\n", "Command: " + sps.shellify(options.jsengineWithArgs) + "\n"]
            + [i + "\n" for i in statusIssueList],
            logPrefix + "-summary.txt",
        )

    if not quiet:
        print logPrefix + " | " + summaryString(issues, lev, runinfo.elapsedtime)
    return lev
コード例 #10
0
def jsfunfuzzLevel(options, logPrefix, quiet=False):
    (lev, issues, runinfo) = baseLevel(options.jsengineWithArgs,
                                       options.timeout,
                                       options.knownPath,
                                       logPrefix,
                                       valgrind=options.valgrind)

    if lev == JS_FINE:
        # Check for unexplained exits and for jsfunfuzz saying "Found a bug".
        understoodExit = False

        # Read in binary mode, because otherwise Python on Windows will
        # throw a fit when it encounters certain unicode.  Note that this
        # makes line endings platform-specific.

        if '-dm-' in options.jsengineWithArgs[0]:
            # Since this is an --enable-more-deterministic build, we should get messages on stderr
            # if the shell quit() or terminate() functions are called.
            # (We use a sketchy filename-matching check because it's faster than inspecting the binary.)
            with open(logPrefix + "-err.txt", "rb") as f:
                for line in f:
                    if "terminate called" in line or "quit called" in line:
                        understoodExit = True
                    if "can't allocate region" in line:
                        understoodExit = True
        else:
            understoodExit = True

        with open(logPrefix + "-out.txt", "rb") as f:
            for line in f:
                if line.startswith("It's looking good!") or line.startswith(
                        "jsfunfuzz broke its own scripting environment: "):
                    understoodExit = True
                if line.startswith("Found a bug: "):
                    understoodExit = True
                    if not ("NestTest" in line and oomed(logPrefix)):
                        lev = JS_DECIDED_TO_EXIT
                        issues.append(line.rstrip())
                        # FIXME: if not quiet:
                        # FIXME:     output everything between this line and "jsfunfuzz stopping due to finding a bug."

        if not understoodExit:
            issues.append("jsfunfuzz didn't finish")
            lev = JS_DID_NOT_FINISH

    # FIXME: if not quiet:
    # FIXME:     output the last tryItOut line

    if lev <= JS_ABNORMAL_EXIT:  # JS_ABNORMAL_EXIT and below (inclusive) will be ignored.
        sps.vdump("jsfunfuzzLevel is ignoring a baseLevel of " + str(lev))
        lev = JS_FINE
        issues = []

    if lev != JS_FINE:
        # FIXME: compareJIT failures do not generate this -summary file.
        statusIssueList = []
        for i in issues:
            statusIssueList.append('Status: ' + i)
        assert len(statusIssueList) != 0
        fileManipulation.writeLinesToFile([
            'Number: ' + logPrefix + '\n',
            'Command: ' + sps.shellify(options.jsengineWithArgs) + '\n'
        ] + [i + '\n' for i in statusIssueList], logPrefix + '-summary.txt')

    if not quiet:
        print logPrefix + " | " + summaryString(issues, lev,
                                                runinfo.elapsedtime)
    return lev
コード例 #11
0
ファイル: loopjsfunfuzz.py プロジェクト: shuixi2013/funfuzz
def many_timed_runs(targetTime, wtmpDir, args):
    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)
            return (lithOps.HAPPY, None)

        # 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])
        jsunhappyOptions = jsInteresting.parseOptions(jsInterestingArgs)

        iteration += 1
        logPrefix = sps.normExpUserPath(os.path.join(wtmpDir, "w" + str(iteration)))

        level = jsInteresting.jsfunfuzzLevel(jsunhappyOptions, logPrefix)

        if level != 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(level))
            itest.append("--timeout=" + str(options.timeout))
            itest.append(options.knownPath)
            (lithResult, lithDetails) = pinpoint.pinpoint(itest, logPrefix, options.jsEngine, engineFlags, filenameToReduce,
                                                          options.repo, options.buildOptionsStr, targetTime, level)
            if targetTime:
                return (lithResult, lithDetails)

        else:
            shellIsDeterministic = inspectShell.queryBuildConfiguration(options.jsEngine, 'more-deterministic')
            flagsAreDeterministic = "--dump-bytecode" not in engineFlags and '-D' not in engineFlags
            if options.useCompareJIT and level == jsInteresting.JS_FINE and \
                    shellIsDeterministic and flagsAreDeterministic:
                linesToCompare = jitCompareLines(logPrefix + '-out.txt', "/*FCM*/")
                jitcomparefilename = logPrefix + "-cj-in.js"
                fileManipulation.writeLinesToFile(linesToCompare, jitcomparefilename)
                (lithResult, lithDetails) = compareJIT.compareJIT(options.jsEngine, engineFlags, jitcomparefilename,
                                                                  logPrefix + "-cj", options.knownPath, options.repo,
                                                                  options.buildOptionsStr, options.timeout, targetTime)
                if lithResult == lithOps.HAPPY:
                    os.remove(jitcomparefilename)
                if targetTime and lithResult != lithOps.HAPPY:
                    jsInteresting.deleteLogs(logPrefix)
                    return (lithResult, lithDetails)
            jsInteresting.deleteLogs(logPrefix)