Skip to content

Added a profile for Maglev #507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/Fuzzilli/Fuzzer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public class Fuzzer {
/// Currently active corpus import job, if any.
private var currentCorpusImportJob = CorpusImportJob(corpus: [], mode: .full)

private var iterationsSinceLastInterestingProgram: Int {
public var iterationsSinceLastInterestingProgram: Int {
assert(iterations >= iterationOfLastInteratingSample)
return iterations - iterationOfLastInteratingSample
}
Expand Down
255 changes: 255 additions & 0 deletions Sources/FuzzilliCli/Profiles/MaglevProfile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
import Fuzzilli

fileprivate let GcGenerator = CodeGenerator("GcGenerator") { b in
let type = b.loadString(probability(0.25) ? "major" : "minor")
let execution = b.loadString(probability(0.5) ? "sync" : "async")
b.callFunction(b.callFunction(b.createNamedVariable(forBuiltin: "gc")), withArgs: [b.createObject(with: ["type": type, "execution": execution])])
}

fileprivate let ForceOSRThroughLoopGenerator = RecursiveCodeGenerator("ForceOSRThroughLoopGenerator") { b in
let numIterations = 100
b.buildRepeatLoop(n: numIterations) { i in
b.buildRecursive()
let selectedIteration = withEqualProbability({
assert(numIterations > 10)
return Int.random(in: (numIterations - 10)..<numIterations)
}, {
return Int.random(in: 0..<numIterations)
})
let cond = b.compare(i, with: b.loadInt(Int64(selectedIteration)), using: .equal)
b.buildIf(cond) {
b.eval("%OptimizeOsr()")
}
}
}

fileprivate let MapTransitionFuzzer = ProgramTemplate("MapTransitionFuzzer") { b in
let propertyNames = b.fuzzer.environment.customProperties
assert(Set(propertyNames).isDisjoint(with: b.fuzzer.environment.customMethods))

assert(propertyNames.contains("a"))
let objType = ILType.object(withProperties: ["a"])

func randomProperties(in b: ProgramBuilder) -> ([String], [Variable]) {
if !b.hasVisibleVariables {
b.loadInt(b.randomInt())
}

var properties = ["a"]
var values = [b.randomVariable()]
for _ in 0..<3 {
let property = chooseUniform(from: propertyNames)
guard !properties.contains(property) else { continue }
properties.append(property)
values.append(b.randomVariable())
}
assert(Set(properties).count == values.count)
return (properties, values)
}

let primitiveValueGenerator = ValueGenerator("PrimitiveValue") { b, n in
for _ in 0..<n {
withEqualProbability({
b.loadInt(b.randomInt())
}, {
b.loadFloat(b.randomFloat())
}, {
b.loadString(b.randomString())
})
}
}
let createObjectGenerator = ValueGenerator("CreateObject") { b, n in
for _ in 0..<n {
let (properties, values) = randomProperties(in: b)
let obj = b.createObject(with: Dictionary(uniqueKeysWithValues: zip(properties, values)))
assert(b.type(of: obj).Is(objType))
}
}
let objectMakerGenerator = ValueGenerator("ObjectMaker") { b, n in
let f = b.buildPlainFunction(with: b.randomParameters()) { args in
let (properties, values) = randomProperties(in: b)
let o = b.createObject(with: Dictionary(uniqueKeysWithValues: zip(properties, values)))
b.doReturn(o)
}
for _ in 0..<n {
let obj = b.callFunction(f, withArgs: b.randomArguments(forCalling: f))
assert(b.type(of: obj).Is(objType))
}
}
let objectConstructorGenerator = ValueGenerator("ObjectConstructor") { b, n in
let c = b.buildConstructor(with: b.randomParameters()) { args in
let this = args[0]
let (properties, values) = randomProperties(in: b)
for (p, v) in zip(properties, values) {
b.setProperty(p, of: this, to: v)
}
}
for _ in 0..<n {
let obj = b.construct(c, withArgs: b.randomArguments(forCalling: c))
assert(b.type(of: obj).Is(objType))
}
}
let objectClassGenerator = ValueGenerator("ObjectClassGenerator") { b, n in
let superclass = b.hasVisibleVariables && probability(0.5) ? b.randomVariable(ofType: .constructor()) : nil
let (properties, values) = randomProperties(in: b)
let cls = b.buildClassDefinition(withSuperclass: superclass) { cls in
for (p, v) in zip(properties, values) {
cls.addInstanceProperty(p, value: v)
}
}
for _ in 0..<n {
let obj = b.construct(cls)
assert(b.type(of: obj).Is(objType))
}
}
let propertyLoadGenerator = CodeGenerator("PropertyLoad", inputs: .required(objType)) { b, obj in
assert(b.type(of: obj).Is(objType))
b.getProperty(chooseUniform(from: propertyNames), of: obj)
}
let propertyStoreGenerator = CodeGenerator("PropertyStore", inputs: .required(objType)) { b, obj in
assert(b.type(of: obj).Is(objType))
let numProperties = Int.random(in: 1...3)
for _ in 0..<numProperties {
b.setProperty(chooseUniform(from: propertyNames), of: obj, to: b.randomVariable())
}
}
let propertyConfigureGenerator = CodeGenerator("PropertyConfigure", inputs: .required(objType)) { b, obj in
assert(b.type(of: obj).Is(objType))
b.configureProperty(chooseUniform(from: propertyNames), of: obj, usingFlags: PropertyFlags.random(), as: .value(b.randomVariable()))
}
let functionDefinitionGenerator = RecursiveCodeGenerator("FunctionDefinition") { b in
var parameters = b.randomParameters()
let haveVisibleObjects = b.visibleVariables.contains(where: { b.type(of: $0).Is(objType) })
if probability(0.5) && haveVisibleObjects {
parameters = .parameters(.plain(objType), .plain(objType), .anything, .anything)
}

let f = b.buildPlainFunction(with: parameters) { params in
b.buildRecursive()
b.doReturn(b.randomVariable())
}

for _ in 0..<3 {
b.callFunction(f, withArgs: b.randomArguments(forCalling: f))
}
}
let functionCallGenerator = CodeGenerator("FunctionCall", inputs: .required(.function())) { b, f in
assert(b.type(of: f).Is(.function()))
let rval = b.callFunction(f, withArgs: b.randomArguments(forCalling: f))
}
let constructorCallGenerator = CodeGenerator("ConstructorCall", inputs: .required(.constructor())) { b, c in
assert(b.type(of: c).Is(.constructor()))
let rval = b.construct(c, withArgs: b.randomArguments(forCalling: c))
}
let functionJitCallGenerator = CodeGenerator("FunctionJitCall", inputs: .required(.function())) { b, f in
assert(b.type(of: f).Is(.function()))
let args = b.randomArguments(forCalling: f)
b.buildRepeatLoop(n: 100) { _ in
b.callFunction(f, withArgs: args)
}
}

let prevCodeGenerators = b.fuzzer.codeGenerators
b.fuzzer.setCodeGenerators(WeightedList<CodeGenerator>([
(primitiveValueGenerator, 2),
(createObjectGenerator, 1),
(objectMakerGenerator, 1),
(objectConstructorGenerator, 1),
(objectClassGenerator, 1),

(propertyStoreGenerator, 10),
(propertyLoadGenerator, 10),
(propertyConfigureGenerator, 5),
(functionDefinitionGenerator, 2),
(functionCallGenerator, 3),
(constructorCallGenerator, 2),
(functionJitCallGenerator, 2)
]))

b.buildPrefix()
b.build(n: 100, by: .generating)

b.fuzzer.setCodeGenerators(prevCodeGenerators)
b.build(n: 10)

for obj in b.visibleVariables where b.type(of: obj).Is(objType) {
b.eval("%HeapObjectVerify(%@)", with: [obj])
}
}

fileprivate let ForceMaglevCompilationGenerator = CodeGenerator("ForceMaglevCompilationGenerator", inputs: .required(.function())) { b, f in
assert(b.type(of: f).Is(.function()))
let arguments = b.randomArguments(forCalling: f)

b.callFunction(f, withArgs: arguments)

b.eval("%PrepareFunctionForOptimization(%@)", with: [f])

b.callFunction(f, withArgs: arguments)
b.callFunction(f, withArgs: arguments)

b.eval("%OptimizeMaglevOnNextCall(%@)", with: [f])

b.callFunction(f, withArgs: arguments)
}

let maglevProfile = Profile(
processArgs: { (randomize) in
var args = [
"--expose-gc",
"--omit-quit",
"--allow-natives-syntax",
"--fuzzing",
"--jit-fuzzing",
// "--future",
"--harmony",
"--js-staging",
"--concurrent-maglev-max-threads=1",
"--no-concurrent_recompilation",
]

guard randomize else { return args; }

return args;
},

processEnv: [:],
maxExecsBeforeRespawn: 1000,
timeout: 250,

codePrefix: """
fuzzilli(\"FUZZILLI_PROBABILITY\", 0.2);

// -------- BEGIN --------
""",
codeSuffix: "",

ecmaVersion: ECMAScriptVersion.es6,
startupTests: [
("fuzzilli('FUZZILLI_PRINT', 'test')", .shouldSucceed),

("fuzzilli('FUZZILLI_CRASH', 0)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 1)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 2)", .shouldCrash),
("fuzzilli('FUZZILLI_CRASH', 3)", .shouldCrash),
],

additionalCodeGenerators: [
(GcGenerator, 10),
(ForceMaglevCompilationGenerator, 5),
(ForceOSRThroughLoopGenerator, 5),
],
additionalProgramTemplates: WeightedList<ProgramTemplate>([
(MapTransitionFuzzer, 1),
]),

disabledCodeGenerators: [],
disabledMutators: [],

additionalBuiltins: [
"gc" : .function([] => (.undefined | .jsPromise))
],

additionalObjectGroups: [],
optionalPostProcessor: nil
)
1 change: 1 addition & 0 deletions Sources/FuzzilliCli/Profiles/Profile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ let profiles = [
"v8holefuzzing": v8HoleFuzzingProfile,
"serenity": serenityProfile,
"njs": njsProfile,
"maglev": maglevProfile
]
1 change: 1 addition & 0 deletions Sources/FuzzilliCli/TerminalUI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class TerminalUI {
Fuzzer Overhead: \(String(format: "%.2f", stats.fuzzerOverhead * 100))%
Minimization Overhead: \(String(format: "%.2f", stats.minimizationOverhead * 100))%
Total Execs: \(stats.totalExecs)
Interations since last: \(fuzzer.iterationsSinceLastInterestingProgram)
""")
}

Expand Down
16 changes: 10 additions & 6 deletions Sources/FuzzilliCli/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Options:
--tag=tag : Optional string tag associated with this instance which will be stored in the settings.json file as well as in crashing samples.
This can for example be used to remember the target revision that is being fuzzed.
--wasm : Enable Wasm CodeGenerators (see WasmCodeGenerators.swift).
--builtinTemplates : Use built-in templates also

""")
exit(0)
Expand Down Expand Up @@ -154,6 +155,7 @@ let swarmTesting = args.has("--swarmTesting")
let argumentRandomization = args.has("--argumentRandomization")
let additionalArguments = args["--additionalArguments"] ?? ""
let tag = args["--tag"]
let builtinTemplates = args["--builtinTemplate"]
let enableWasm = args.has("--wasm")

guard numJobs >= 1 else {
Expand Down Expand Up @@ -447,13 +449,15 @@ func makeFuzzer(with configuration: Configuration) -> Fuzzer {
}
}

for template in ProgramTemplates {
guard let weight = programTemplateWeights[template.name] else {
print("Missing weight for program template \(template.name) in ProgramTemplateWeights.swift")
exit(-1)
}
if builtinTemplates != nil {
for template in ProgramTemplates {
guard let weight = programTemplateWeights[template.name] else {
print("Missing weight for program template \(template.name) in ProgramTemplateWeights.swift")
exit(-1)
}

programTemplates.append(template, withWeight: weight)
programTemplates.append(template, withWeight: weight)
}
}

// The environment containing available builtins, property names, and method names.
Expand Down