Skip to content

Commit b5aeee8

Browse files
author
Samuel Groß
committed
Make it possible to import .js files that throw an exception
Previously, we wouldn't import those files as we require all samples in the corpus to execute successfully. With this change, we simply try to wrap all failing programs in a big try-catch block during corpus import, then try importing them again. In the future we could improve this mechanism to for example determine exactly which instruction causes the exception and then either remove this instruction or wrap (only) it in a try-catch. But for now, this simple change already allows us to import ~30% more programs from V8's regression tests. Drive-By: add some more functions to filteredFunctionsForCompiler.
1 parent 4a3e3da commit b5aeee8

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

Sources/FuzzILTool/main.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,15 @@ let fuzzILLifter = FuzzILLifter()
2727
// Default list of functions that are filtered out during compilation. These are functions that may be used in testcases but which do not influence the test's behaviour and so should be omitted for fuzzing.
2828
// The functions can use the wildcard '*' character as _last_ character, in which case a prefix match will be performed.
2929
let filteredFunctionsForCompiler = [
30+
// Functions used in V8's test suite
3031
"assert*",
3132
"print*",
33+
// Functions used in Mozilla's test suite
34+
"startTest",
3235
"enterFunc",
33-
"startTest"
36+
"exitFunc",
37+
"report*",
38+
"options*",
3439
]
3540

3641
// Loads a serialized FuzzIL program from the given file

Sources/Fuzzilli/Fuzzer.swift

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,18 +641,36 @@ public class Fuzzer {
641641

642642
case .corpusImport:
643643
assert(!currentCorpusImportJob.isFinished)
644-
let program = currentCorpusImportJob.nextProgram()
644+
var program = currentCorpusImportJob.nextProgram()
645645

646646
if currentCorpusImportJob.numberOfProgramsImportedSoFar % 500 == 0 {
647647
logger.info("Corpus import progress: imported \(currentCorpusImportJob.numberOfProgramsImportedSoFar) of \(currentCorpusImportJob.totalNumberOfProgramsToImport) programs")
648648
}
649649

650-
let outcome = importProgram(program, origin: .corpusImport(mode: currentCorpusImportJob.importMode))
650+
var outcome = importProgram(program, origin: .corpusImport(mode: currentCorpusImportJob.importMode))
651+
if case .failed = outcome {
652+
// Wrap the entire program in a try-catch block and retry.
653+
// TODO we could be a lot smarter here. For example, we could instrument the program to determine
654+
// exactly which instruction causes the exception to be thrown, and then either delete that
655+
// instruction or wrap just that instruction in try-catch.
656+
let b = makeBuilder()
657+
b.buildTryCatchFinally(tryBody: {
658+
b.adopting(from: program) {
659+
for instr in program.code {
660+
b.adopt(instr)
661+
}
662+
}
663+
}, catchBody: { _ in })
664+
program = b.finalize()
665+
currentCorpusImportJob.notifyProgramNeededFixup()
666+
outcome = importProgram(program, origin: .corpusImport(mode: currentCorpusImportJob.importMode))
667+
}
651668
currentCorpusImportJob.notifyImportOutcome(outcome)
652669

653670
if currentCorpusImportJob.isFinished {
654671
logger.info("Corpus import finished:")
655672
logger.info("\(currentCorpusImportJob.numberOfProgramsThatExecutedSuccessfullyDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs executed successfully during import")
673+
logger.info("\(currentCorpusImportJob.numberOfProgramsThatNeededFixup)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs needed fixup during import (wrapping in try-catch)")
656674
logger.info("\(currentCorpusImportJob.numberOfProgramsThatTimedOutDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs timed out during import")
657675
logger.info("\(currentCorpusImportJob.numberOfProgramsThatFailedDuringImport)/\(currentCorpusImportJob.totalNumberOfProgramsToImport) programs failed to execute during import")
658676
logger.info("Corpus now contains \(corpus.size) programs")
@@ -799,6 +817,7 @@ public class Fuzzer {
799817
private(set) var numberOfProgramsThatFailedDuringImport = 0
800818
private(set) var numberOfProgramsThatTimedOutDuringImport = 0
801819
private(set) var numberOfProgramsThatExecutedSuccessfullyDuringImport = 0
820+
private(set) var numberOfProgramsThatNeededFixup = 0
802821

803822
init(corpus: [Program], mode: CorpusImportMode) {
804823
self.corpusToImport = corpus.reversed() // Programs are taken from the end.
@@ -830,6 +849,10 @@ public class Fuzzer {
830849
}
831850
}
832851

852+
mutating func notifyProgramNeededFixup() {
853+
numberOfProgramsThatNeededFixup += 1
854+
}
855+
833856
func progress() -> Double {
834857
let numberOfProgramsToImport = Double(totalNumberOfProgramsToImport)
835858
let numberOfProgramsAlreadyImported = Double(numberOfProgramsImportedSoFar)

0 commit comments

Comments
 (0)