Skip to content

Commit 28daab0

Browse files
author
Samuel Groß
committed
Refactor the Environment protocol
This commit changes two things: 1) It refactors the sets of property and method names exposed by the environment. Now there are simply four sets: customProperties and customMethods, wich are properties/methods that should be used when defining properties/methods on objects, and builtinProperties and builtinMethods which are properties/methods that exist on builtin objects. When adding new properties/methods to an object we now always select the name from the customProperties/Methods sets. Furthermore, when not having static type information, we now also prefer to pick a random method from the customProperties/Methods set as there will be a higher chance of success. 2) It removes some properties from builtin objects in the environment model. Basically, we now only want to model properties/methods that are unique to one object type (e.g. "byteLength"), and not those that are common to many different object types (e.g. "constructor"). Otherwise, for example for Arrays we'd have a 50/50 chance of picking "length" (probably relevant) or "constructor" (probably less relevant). For common properties that should still be accessed, e.g. "__proto__" we rely on CodeGenerators or the ExplorationMutator.
1 parent d82f236 commit 28daab0

23 files changed

Lines changed: 348 additions & 244 deletions

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,9 @@ public class ProgramBuilder {
213213
/// Returns a random string value.
214214
public func randString() -> String {
215215
return withEqualProbability({
216-
self.randPropertyForReading()
216+
self.randPropertyName()
217+
}, {
218+
self.randMethodName()
217219
}, {
218220
chooseUniform(from: self.fuzzer.environment.interestingStrings)
219221
}, {
@@ -268,39 +270,56 @@ public class ProgramBuilder {
268270
return chooseUniform(from: fuzzer.environment.builtins)
269271
}
270272

271-
/// Returns the name of a random property suitable for read access.
272-
public func randPropertyForReading() -> String {
273-
return chooseUniform(from: fuzzer.environment.readableProperties)
273+
/// Returns a random builtin property name.
274+
///
275+
/// This will return a random name from the environment's list of builtin property names,
276+
/// i.e. a property that exists on (at least) one builtin object type.
277+
func randBuiltinPropertyName() -> String {
278+
return chooseUniform(from: fuzzer.environment.builtinProperties)
274279
}
275280

276-
/// Returns the name of a random property suitable for write access.
277-
public func randPropertyForWriting() -> String {
278-
return chooseUniform(from: fuzzer.environment.writableProperties)
281+
/// Returns a random custom property name.
282+
///
283+
/// This will select a random property from a (usually relatively small) set of custom property names defined by the environment.
284+
///
285+
/// This should generally be used in one of two situations:
286+
/// 1. If a new property is added to an object.
287+
/// In that case, we prefer to add properties with custom names (e.g. ".a", ".b") instead of properties
288+
/// with names that exist in the environment (e.g. ".length", ".prototype"). This way, in the resulting code
289+
/// it will be fairly clear when a builtin property is accessed vs. a custom one. It also increases the chances
290+
/// of selecting an existing property when choosing a random property to access, see the next point.
291+
/// 2. If we have no static type information about the object we're accessing.
292+
/// In that case there is a higher chance of success when using the small set of custom property names
293+
/// instead of the much larger set of all property names that exist in the environment (or something else).
294+
public func randCustomPropertyName() -> String {
295+
return chooseUniform(from: fuzzer.environment.customProperties)
279296
}
280297

281-
/// Returns the name of a random property suitable for defining on new objects.
282-
public func randPropertyForDefining() -> String {
283-
if probability(0.5) {
284-
return randPropertyForWriting()
285-
} else {
286-
return chooseUniform(from: fuzzer.environment.customProperties)
287-
}
298+
/// Returns either a builtin or a custom property name, with equal probability.
299+
public func randPropertyName() -> String {
300+
return probability(0.5) ? randBuiltinPropertyName() : randCustomPropertyName()
288301
}
289302

290-
/// Returns the name of a random method.
291-
public func randMethod() -> String {
292-
return chooseUniform(from: fuzzer.environment.methods)
303+
/// Returns a random builtin method name.
304+
///
305+
/// This will return a random name from the environment's list of builtin method names,
306+
/// i.e. a method that exists on (at least) one builtin object type.
307+
public func randBuiltinMethodName() -> String {
308+
return chooseUniform(from: fuzzer.environment.builtinMethods)
293309
}
294310

295-
/// Returns the name of a random method suitable for defining on new objects.
296-
public func randMethodForDefining() -> String {
297-
if probability(0.10) {
298-
// TODO should there be a environment.writableMethods that includes the custom method
299-
// names and things like valueOf, etc. Maybe it's ok since they are in writableProperties...
300-
return randMethod()
301-
} else {
302-
return chooseUniform(from: fuzzer.environment.customMethods)
303-
}
311+
/// Returns a random custom method name.
312+
///
313+
/// This will select a random method from a (usually relatively small) set of custom method names defined by the environment.
314+
///
315+
/// See the comment for randCustomPropertyName() for when this should be used.
316+
public func randCustomMethodName() -> String {
317+
return chooseUniform(from: fuzzer.environment.customMethods)
318+
}
319+
320+
/// Returns either a builtin or a custom method name, with equal probability.
321+
public func randMethodName() -> String {
322+
return probability(0.5) ? randBuiltinMethodName() : randCustomMethodName()
304323
}
305324

306325

@@ -1357,6 +1376,8 @@ public class ProgramBuilder {
13571376
fileprivate var existingGetters: [String] = []
13581377
fileprivate var existingSetters: [String] = []
13591378

1379+
public fileprivate(set) var hasPrototype = false
1380+
13601381
fileprivate init(in b: ProgramBuilder) {
13611382
assert(b.context.contains(.objectLiteral))
13621383
self.b = b
@@ -1389,26 +1410,36 @@ public class ProgramBuilder {
13891410
public func addProperty(_ name: String, as value: Variable) {
13901411
b.emit(ObjectLiteralAddProperty(propertyName: name), withInputs: [value])
13911412
}
1413+
13921414
public func addElement(_ index: Int64, as value: Variable) {
13931415
b.emit(ObjectLiteralAddElement(index: index), withInputs: [value])
13941416
}
1417+
13951418
public func addComputedProperty(_ name: Variable, as value: Variable) {
13961419
b.emit(ObjectLiteralAddComputedProperty(), withInputs: [name, value])
13971420
}
1421+
13981422
public func copyProperties(from obj: Variable) {
13991423
b.emit(ObjectLiteralCopyProperties(), withInputs: [obj])
14001424
}
1425+
1426+
public func setPrototype(to proto: Variable) {
1427+
b.emit(ObjectLiteralSetPrototype(), withInputs: [proto])
1428+
}
1429+
14011430
public func addMethod(_ name: String, with descriptor: SubroutineDescriptor, _ body: ([Variable]) -> ()) {
14021431
b.setSignatureForNextFunction(descriptor.signature)
14031432
let instr = b.emit(BeginObjectLiteralMethod(methodName: name, parameters: descriptor.parameters))
14041433
body(Array(instr.innerOutputs))
14051434
b.emit(EndObjectLiteralMethod())
14061435
}
1436+
14071437
public func addGetter(for name: String, _ body: (_ this: Variable) -> ()) {
14081438
let instr = b.emit(BeginObjectLiteralGetter(propertyName: name))
14091439
body(instr.innerOutput)
14101440
b.emit(EndObjectLiteralGetter())
14111441
}
1442+
14121443
public func addSetter(for name: String, _ body: (_ this: Variable, _ val: Variable) -> ()) {
14131444
let instr = b.emit(BeginObjectLiteralSetter(propertyName: name))
14141445
body(instr.innerOutput(0), instr.innerOutput(1))
@@ -2294,6 +2325,8 @@ public class ProgramBuilder {
22942325
case .objectLiteralCopyProperties:
22952326
// Cannot generally determine what fields this installs.
22962327
break
2328+
case .objectLiteralSetPrototype:
2329+
currentObjectLiteral.hasPrototype = true
22972330
case .beginObjectLiteralMethod(let op):
22982331
currentObjectLiteral.existingMethods.append(op.methodName)
22992332
case .beginObjectLiteralGetter(let op):

0 commit comments

Comments
 (0)