Skip to content

Commit a61ae38

Browse files
committed
Merge upstream/main (60 commits from googleprojectzero)
Profiles moved from FuzzilliCli/Profiles to Fuzzilli/Profiles. BunProfile.swift moved and import adjusted. .github/workflows/swift.yml reverted (OAuth lacks workflow scope; upstream changes were trivial -v flags and apt update).
2 parents 66dc0cc + 2b9cdba commit a61ae38

55 files changed

Lines changed: 2403 additions & 718 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ let package = Package(
8282
.executableTarget(name: "RelateTool",
8383
dependencies: ["Fuzzilli"]),
8484

85+
.executableTarget(name: "FuzzilliDetectMissingBuiltins", dependencies: ["Fuzzilli"]),
86+
8587
.testTarget(name: "FuzzilliTests",
8688
dependencies: ["Fuzzilli"],
8789
resources: [.copy("CompilerTests")]),

Sources/Fuzzilli/Base/Logging.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public enum LogLevel: Int {
2828

2929
/// Logs messages to the active fuzzer instance or prints them to stdout if no fuzzer is active.
3030
public class Logger {
31+
public static var defaultLogLevelWithoutFuzzer = LogLevel.verbose
3132
private let label: String
3233

3334
public init(withLabel label: String) {
@@ -39,7 +40,7 @@ public class Logger {
3940
if fuzzer.config.logLevel.isAtLeast(level) {
4041
fuzzer.dispatchEvent(fuzzer.events.Log, data: (fuzzer.id, level, label, message))
4142
}
42-
} else {
43+
} else if Logger.defaultLogLevelWithoutFuzzer.isAtLeast(level) {
4344
print("[\(label)] \(message)")
4445
}
4546
}

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 127 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,13 @@ public class ProgramBuilder {
487487
return chooseUniform(from: fuzzer.environment.customMethods)
488488
}
489489

490+
/// Returns a random custom private method name.
491+
///
492+
/// As above but for private methods, where a # symbol will be prepended.
493+
public func randomCustomPrivateMethodName() -> String {
494+
return chooseUniform(from: fuzzer.environment.customPrivateMethods)
495+
}
496+
490497
/// Returns either a builtin or a custom method name, with equal probability.
491498
public func randomMethodName() -> String {
492499
return probability(0.5) ? randomBuiltinMethodName() : randomCustomMethodName()
@@ -730,6 +737,7 @@ public class ProgramBuilder {
730737
let (pattern, flags) = self.randomRegExpPatternAndFlags()
731738
return self.loadRegExp(pattern, flags)
732739
}),
740+
(.iterable, { return self.createArray(with: [self.randomJsVariable()]) }),
733741
(.function(), {
734742
// TODO: We could technically generate a full function here but then we would enter the full code generation logic which could do anything.
735743
// Because we want to avoid this, we will just pick anything that can be a function.
@@ -3779,7 +3787,7 @@ public class ProgramBuilder {
37793787

37803788
public func wasmReturnCallDirect(signature: WasmSignature, function: Variable, functionArgs: [Variable]) {
37813789
assert(self.signature.outputTypes == signature.outputTypes)
3782-
b.emit(WasmReturnCallDirect(signature: signature),
3790+
b.emit(WasmReturnCallDirect(parameterCount: signature.parameterTypes.count),
37833791
withInputs: [function] + functionArgs,
37843792
types: [.wasmFunctionDef(signature)] + signature.parameterTypes)
37853793
}
@@ -3794,8 +3802,9 @@ public class ProgramBuilder {
37943802

37953803
@discardableResult
37963804
public func wasmJsCall(function: Variable, withArgs args: [Variable], withWasmSignature signature: WasmSignature) -> Variable? {
3797-
let instr = b.emit(WasmJsCall(signature: signature), withInputs: [function] + args,
3798-
types: [.function() | .object(ofGroup: "WasmSuspendingObject")] + signature.parameterTypes)
3805+
let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature)
3806+
let instr = b.emit(WasmJsCall(parameterCount: signature.parameterTypes.count, outputCount: signature.outputTypes.count), withInputs: [signatureDef, function] + args,
3807+
types: [.wasmTypeDef(), .function() | .object(ofGroup: "WasmSuspendingObject")] + signature.parameterTypes)
37993808
if signature.outputTypes.isEmpty {
38003809
assert(!instr.hasOutputs)
38013810
return nil
@@ -3915,11 +3924,6 @@ public class ProgramBuilder {
39153924
b.emit(WasmReassign(), withInputs: [variable, to])
39163925
}
39173926

3918-
public enum wasmBlockType {
3919-
case typeIdx(Int)
3920-
case valueType(ILType)
3921-
}
3922-
39233927
// The first innerOutput of this block is a label variable, which is just there to explicitly mark control-flow and allow branches.
39243928
public func wasmBuildBlock(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> ()) {
39253929
assert(signature.outputTypes.count == 0)
@@ -4436,10 +4440,18 @@ public class ProgramBuilder {
44364440

44374441
@discardableResult
44384442
public func wasmRefTest(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable {
4439-
typeDef == nil
4440-
? b.emit(WasmRefTest(refType: refType), withInputs: [ref]).output
4441-
: b.emit(WasmRefTest(refType: refType), withInputs: [ref, typeDef!]).output
4443+
let inputs = typeDef == nil ? [ref] : [ref, typeDef!]
4444+
let types: [ILType] = typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()]
4445+
return b.emit(WasmRefTest(refType: refType), withInputs: inputs, types: types).output
4446+
}
4447+
4448+
@discardableResult
4449+
public func wasmRefCast(_ ref: Variable, refType: ILType, typeDef: Variable? = nil) -> Variable {
4450+
let inputs = typeDef == nil ? [ref] : [ref, typeDef!]
4451+
let types: [ILType] = typeDef == nil ? [.wasmGenericRef] : [.wasmGenericRef, .wasmTypeDef()]
4452+
return b.emit(WasmRefCast(refType: refType), withInputs: inputs, types: types).output
44424453
}
4454+
44434455
}
44444456

44454457
public class WasmModule {
@@ -4595,6 +4607,29 @@ public class ProgramBuilder {
45954607
return (dynamicOffset, alignedStaticOffset)
45964608
}
45974609

4610+
func generateRandomWasmStructFields() -> (fields: [WasmStructTypeDescription.Field], indexTypes: [Variable]) {
4611+
var indexTypes: [Variable] = []
4612+
4613+
let fields = (0..<Int.random(in: 0...10)).map { _ in
4614+
var type: ILType
4615+
// TODO(mliedtke): Allow non-nullable reference types. Right now we can't do this as
4616+
// the WasmStructNewGenerator might then fail to generate a struct.
4617+
let nullability = true
4618+
if let elementType = randomVariable(ofType: .wasmTypeDef()), probability(0.25) {
4619+
indexTypes.append(elementType)
4620+
type = .wasmRef(.Index(), nullability: nullability)
4621+
} else {
4622+
type = chooseUniform(from: [
4623+
.wasmPackedI8, .wasmPackedI16, .wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128,
4624+
] + WasmAbstractHeapType.allCases.map {ILType.wasmRef($0, nullability: nullability)})
4625+
}
4626+
return WasmStructTypeDescription.Field(
4627+
type: type, mutability: probability(0.75))
4628+
}
4629+
4630+
return (fields, indexTypes)
4631+
}
4632+
45984633
/// Produces a WasmGlobal that is valid to create in the given Context.
45994634
public func randomWasmGlobal(forContext context: Context) -> WasmGlobal {
46004635
// TODO(pawkra): enable shared element types.
@@ -4669,8 +4704,9 @@ public class ProgramBuilder {
46694704
indexTypes.append(elementType)
46704705
return ILType.wasmRef(.Index(), nullability: nullability)
46714706
} else {
4672-
// TODO(mliedtke): Extend list with abstract heap types.
4673-
return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128])
4707+
let nullability = !allowNonNullable || probability(0.5)
4708+
return chooseUniform(from: [.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128]
4709+
+ WasmAbstractHeapType.allCases.map {ILType.wasmRef($0, nullability: nullability)})
46744710
}
46754711
}
46764712
let signature = (0..<parameterCount).map {_ in chooseType()}
@@ -5009,22 +5045,28 @@ public class ProgramBuilder {
50095045
// so we instead register a generator that allows the fuzzer a greater chance of generating
50105046
// one when needed.
50115047
//
5012-
// These can be registered on the JavaScriptEnvironment with addProducingGenerator()
5048+
// These can be registered on the JavaScriptEnvironment with addProducingGenerator().
5049+
// argument `predefined`: Provide values that should be used for the given properties of the
5050+
// options bag (if present) instead of finding or generating random values for them. The
5051+
// property might still be filtered out.
50135052
@discardableResult
5014-
func createOptionsBag(_ bag: OptionsBag) -> Variable {
5053+
func createOptionsBag(_ bag: OptionsBag, predefined: [String: Variable] = [:]) -> Variable {
50155054
// We run .filter() to pick a subset of fields, but we generally want to set as many as possible
50165055
// and let the mutator prune things
5017-
let dict: [String : Variable] = bag.properties.filter {_ in probability(0.8)}.mapValues {
5018-
if $0.isEnumeration {
5019-
return loadEnum($0)
5056+
let dict = [String : Variable](uniqueKeysWithValues: bag.properties.filter {_ in probability(0.8)}.map {
5057+
let (propertyName, type) = $0
5058+
if let predefinedVar = predefined[propertyName] {
5059+
return (propertyName, predefinedVar)
5060+
} else if type.isEnumeration {
5061+
return (propertyName, loadEnum(type))
50205062
// relativeTo doesn't have an ObjectGroup so we cannot just register a producingGenerator for it
5021-
} else if $0.Is(OptionsBag.jsTemporalRelativeTo) {
5022-
return findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime,
5023-
.jsTemporalPlainDate, .string]))
5063+
} else if type.Is(OptionsBag.jsTemporalRelativeTo) {
5064+
return (propertyName, findOrGenerateType(chooseUniform(from: [.jsTemporalZonedDateTime, .jsTemporalPlainDateTime,
5065+
.jsTemporalPlainDate, .string])))
50245066
} else {
5025-
return findOrGenerateType($0)
5067+
return (propertyName, findOrGenerateType(type))
50265068
}
5027-
}
5069+
})
50285070
return createObject(with: dict)
50295071
}
50305072

@@ -5393,6 +5435,29 @@ public class ProgramBuilder {
53935435
fileprivate static let allScripts = ["Adlm", "Afak", "Aghb", "Ahom", "Arab", "Aran", "Armi", "Armn", "Avst", "Bali", "Bamu", "Bass", "Batk", "Beng", "Berf", "Bhks", "Blis", "Bopo", "Brah", "Brai", "Bugi", "Buhd", "Cakm", "Cans", "Cari", "Cham", "Cher", "Chis", "Chrs", "Cirt", "Copt", "Cpmn", "Cprt", "Cyrl", "Cyrs", "Deva", "Diak", "Dogr", "Dsrt", "Dupl", "Egyd", "Egyh", "Egyp", "Elba", "Elym", "Ethi", "Gara", "Geok", "Geor", "Glag", "Gong", "Gonm", "Goth", "Gran", "Grek", "Gujr", "Gukh", "Guru", "Hanb", "Hang", "Hani", "Hano", "Hans", "Hant", "Hatr", "Hebr", "Hira", "Hluw", "Hmng", "Hmnp", "Hntl", "Hrkt", "Hung", "Inds", "Ital", "Jamo", "Java", "Jpan", "Jurc", "Kali", "Kana", "Kawi", "Khar", "Khmr", "Khoj", "Kitl", "Kits", "Knda", "Kore", "Kpel", "Krai", "Kthi", "Lana", "Laoo", "Latf", "Latg", "Latn", "Leke", "Lepc", "Limb", "Lina", "Linb", "Lisu", "Loma", "Lyci", "Lydi", "Mahj", "Maka", "Mand", "Mani", "Marc", "Maya", "Medf", "Mend", "Merc", "Mero", "Mlym", "Modi", "Mong", "Moon", "Mroo", "Mtei", "Mult", "Mymr", "Nagm", "Nand", "Narb", "Nbat", "Newa", "Nkdb", "Nkgb", "Nkoo", "Nshu", "Ogam", "Olck", "Onao", "Orkh", "Orya", "Osge", "Osma", "Ougr", "Palm", "Pauc", "Pcun", "Pelm", "Perm", "Phag", "Phli", "Phlp", "Phlv", "Phnx", "Piqd", "Plrd", "Prti", "Psin", "Qaaa-Qabx", "Ranj", "Rjng", "Rohg", "Roro", "Runr", "Samr", "Sara", "Sarb", "Saur", "Seal", "Sgnw", "Shaw", "Shrd", "Shui", "Sidd", "Sidt", "Sind", "Sinh", "Sogd", "Sogo", "Sora", "Soyo", "Sund", "Sunu", "Sylo", "Syrc", "Syre", "Syrj", "Syrn", "Tagb", "Takr", "Tale", "Talu", "Taml", "Tang", "Tavt", "Tayo", "Telu", "Teng", "Tfng", "Tglg", "Thaa", "Thai", "Tibt", "Tirh", "Tnsa", "Todr", "Tols", "Toto", "Tutg", "Ugar", "Vaii", "Visp", "Vith", "Wara", "Wcho", "Wole", "Xpeo", "Xsux", "Yezi", "Yiii", "Zanb", "Zinh", "Zmth", "Zsye", "Zsym", "Zxxx", "Zyyy", "Zzzz"]
53945436
fileprivate static let allAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
53955437
fileprivate static let allAlphaNum = allAlpha + "0123456789"
5438+
fileprivate static let allRegionsTwoDigit = [
5439+
"AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT",
5440+
"AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI",
5441+
"BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY",
5442+
"BZ", "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN",
5443+
"CO", "CR", "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM",
5444+
"DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK",
5445+
"FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL",
5446+
"GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM",
5447+
"HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR",
5448+
"IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN",
5449+
"KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS",
5450+
"LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK",
5451+
"ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW",
5452+
"MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP",
5453+
"NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM",
5454+
"PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW",
5455+
"SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", "SL", "SM",
5456+
"SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TF",
5457+
"TG", "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW",
5458+
"TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI",
5459+
"VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW",
5460+
]
53965461

53975462
@discardableResult
53985463
static func constructIntlUnit() -> String {
@@ -5419,7 +5484,7 @@ public class ProgramBuilder {
54195484
static func constructIntlRegionString() -> String {
54205485
// either two letters or three digits
54215486
if probability(0.5) {
5422-
return String((0..<2).map { _ in allAlpha.randomElement()! })
5487+
return allRegionsTwoDigit.randomElement()!
54235488
} else {
54245489
return String(format: "%03d", Int.random(in: 0...999))
54255490
}
@@ -5485,6 +5550,11 @@ public class ProgramBuilder {
54855550
return constructIntlType(type: "Collator", optionsBag: .jsIntlCollatorSettings)
54865551
}
54875552

5553+
@discardableResult
5554+
func constructIntlDisplayNames() -> Variable {
5555+
return constructIntlType(type: "DisplayNames", optionsBag: .jsIntlDisplayNamesSettings)
5556+
}
5557+
54885558
@discardableResult
54895559
func constructIntlListFormat() -> Variable {
54905560
return constructIntlType(type: "ListFormat", optionsBag: .jsIntlListFormatSettings)
@@ -5509,6 +5579,37 @@ public class ProgramBuilder {
55095579
func constructIntlSegmenter() -> Variable {
55105580
return constructIntlType(type: "Segmenter", optionsBag: .jsIntlSegmenterSettings)
55115581
}
5512-
}
5513-
55145582

5583+
// Fuzz calls with the pattern new Intl.DisplayNames(locale, settings).of(code).
5584+
// These need to be generated together as there is a tight coupling between the `type` property
5585+
// in the settings optionsbag and the valid code values passed to the `of` method.
5586+
@discardableResult
5587+
func fuzzIntlDisplayNamesOf() -> Variable {
5588+
let intl = createNamedVariable(forBuiltin: "Intl")
5589+
let ctor = getProperty("DisplayNames", of: intl)
5590+
let types = fuzzer.environment.getEnum(ofName: "IntlDisplayNamesTypeEnum")!.enumValues
5591+
let type = types.randomElement()!
5592+
let locale = loadString(ProgramBuilder.constructIntlLocaleString())
5593+
let options = createOptionsBag(.jsIntlDisplayNamesSettings,
5594+
predefined: ["type": loadString(type)])
5595+
construct(ctor, withArgs: [locale, options])
5596+
let code = switch type {
5597+
case "language":
5598+
ProgramBuilder.constructIntlLanguageString()
5599+
case "region":
5600+
ProgramBuilder.constructIntlRegionString()
5601+
case "script":
5602+
ProgramBuilder.constructIntlScriptString()
5603+
case "currency":
5604+
Locale.commonISOCurrencyCodes.randomElement()!
5605+
case "calendar":
5606+
fuzzer.environment.getEnum(ofName: "temporalCalendar")!.enumValues.randomElement()!
5607+
case "dateTimeField":
5608+
["era", "year", "quarter", "month", "weekOfYear", "weekday", "day",
5609+
"dayPeriod", "hour", "minute", "second", "timeZoneName"].randomElement()!
5610+
default:
5611+
String.random(ofLength: 4)
5612+
}
5613+
return callMethod("of", on: ctor, withArgs: [loadString(code)])
5614+
}
5615+
}

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,4 +381,6 @@ public let codeGeneratorWeights = [
381381
"WasmExternConvertAnyGenerator": 5,
382382
"WasmRefTestGenerator": 5,
383383
"WasmRefTestAbstractGenerator": 5,
384+
"WasmRefCastGenerator": 5,
385+
"WasmRefCastAbstractGenerator": 5,
384386
]

Sources/Fuzzilli/CodeGen/CodeGenerators.swift

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
import Foundation
16+
1517
// Generator stubs for disposable and async-disposable object variables.
1618
func disposableObjVariableGeneratorStubs(
1719
inContext contextRequirement : Context,
@@ -351,7 +353,18 @@ public let CodeGenerators: [CodeGenerator] = [
351353
},
352354

353355
CodeGenerator("BuiltinIntlGenerator") { b in
354-
let _ = chooseUniform(from: [b.constructIntlDateTimeFormat, b.constructIntlCollator, b.constructIntlListFormat, b.constructIntlLocale, b.constructIntlNumberFormat, b.constructIntlPluralRules, b.constructIntlRelativeTimeFormat, b.constructIntlSegmenter])()
356+
let _ = chooseUniform(from: [
357+
b.constructIntlDateTimeFormat,
358+
b.constructIntlCollator,
359+
b.constructIntlListFormat,
360+
b.constructIntlLocale,
361+
b.constructIntlNumberFormat,
362+
b.constructIntlPluralRules,
363+
b.constructIntlRelativeTimeFormat,
364+
b.constructIntlSegmenter,
365+
b.constructIntlDisplayNames,
366+
b.fuzzIntlDisplayNamesOf,
367+
])()
355368
},
356369

357370
CodeGenerator("HexGenerator") { b in
@@ -1236,8 +1249,8 @@ public let CodeGenerators: [CodeGenerator] = [
12361249
inContext: .single(.classDefinition),
12371250
provides: [.javascript, .subroutine, .method, .classMethod]
12381251
) { b in
1239-
// Try to find a private field that hasn't already been added to this class.
1240-
let methodName = b.generateString(b.randomCustomMethodName,
1252+
// Try to find a private method that hasn't already been added to this class.
1253+
let methodName = b.generateString(b.randomCustomPrivateMethodName,
12411254
notIn: b.currentClassDefinition.privateFields)
12421255
let parameters = b.randomParameters()
12431256
b.emit(
@@ -1273,8 +1286,8 @@ public let CodeGenerators: [CodeGenerator] = [
12731286
inContext: .single(.classDefinition),
12741287
provides: [.javascript, .subroutine, .method, .classMethod]
12751288
) { b in
1276-
// Try to find a private field that hasn't already been added to this class.
1277-
let methodName = b.generateString(b.randomCustomMethodName,
1289+
// Try to find a private method that hasn't already been added to this class.
1290+
let methodName = b.generateString(b.randomCustomPrivateMethodName,
12781291
notIn: b.currentClassDefinition.privateFields)
12791292
let parameters = b.randomParameters()
12801293
b.emit(

0 commit comments

Comments
 (0)