Skip to content

Commit 0cd2f83

Browse files
authored
add support for template literals (googleprojectzero#208)
1 parent 98298d1 commit 0cd2f83

File tree

13 files changed

+172
-0
lines changed

13 files changed

+172
-0
lines changed

Sources/Fuzzilli/Core/CodeGenerators.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ public let CodeGenerators: [CodeGenerator] = [
9797
b.createArray(with: initialValues, spreading: spreads)
9898
},
9999

100+
CodeGenerator("TemplateStringGenerator") { b in
101+
var interpolatedValues = [Variable]()
102+
for _ in 1..<Int.random(in: 1...5) {
103+
interpolatedValues.append(b.randVar())
104+
}
105+
106+
var parts = [String]()
107+
for _ in 0...interpolatedValues.count {
108+
// For now we generate random strings
109+
parts.append(b.genString())
110+
}
111+
b.createTemplateString(from: parts, interpolating: interpolatedValues)
112+
},
113+
100114
CodeGenerator("BuiltinGenerator") { b in
101115
b.loadBuiltin(b.genBuiltinName())
102116
},

Sources/Fuzzilli/Core/ProgramBuilder.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,16 @@ public class ProgramBuilder {
480480
if type.Is(.bigint) || type.Is(fuzzer.environment.bigIntType) {
481481
return loadBigInt(genInt())
482482
}
483+
if type.Is(.function()) {
484+
let signature = type.signature ?? FunctionSignature(withParameterCount: Int.random(in: 2...5), hasRestParam: probability(0.1))
485+
return definePlainFunction(withSignature: signature) { _ in
486+
generateRecursive()
487+
doReturn(value: randVar())
488+
}
489+
}
490+
if type.Is(.regexp) || type.Is(fuzzer.environment.regExpType) {
491+
return loadRegExp(genRegExp(), genRegExpFlags())
492+
}
483493

484494
assert(type.Is(.object()), "Unexpected type encountered \(type)")
485495

@@ -998,6 +1008,11 @@ public class ProgramBuilder {
9981008
return perform(CreateArrayWithSpread(numInitialValues: initialValues.count, spreads: spreads), withInputs: initialValues).output
9991009
}
10001010

1011+
@discardableResult
1012+
public func createTemplateString(from parts: [String], interpolating interpolatedValues: [Variable]) -> Variable {
1013+
return perform(CreateTemplateString(parts: parts), withInputs: interpolatedValues).output
1014+
}
1015+
10011016
@discardableResult
10021017
public func loadBuiltin(_ name: String) -> Variable {
10031018
return perform(LoadBuiltin(builtinName: name)).output

Sources/Fuzzilli/FuzzIL/AbstractInterpreter.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,9 @@ public struct AbstractInterpreter {
362362
is CreateArrayWithSpread:
363363
set(instr.output, environment.arrayType)
364364

365+
case is CreateTemplateString:
366+
set(instr.output, environment.stringType)
367+
365368
case let op as StoreProperty:
366369
if environment.customMethodNames.contains(op.propertyName) {
367370
set(instr.input(0), type(ofInput: 0).adding(method: op.propertyName))

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ extension Instruction: ProtobufConvertible {
290290
$0.createArray = Fuzzilli_Protobuf_CreateArray()
291291
case let op as CreateArrayWithSpread:
292292
$0.createArrayWithSpread = Fuzzilli_Protobuf_CreateArrayWithSpread.with { $0.spreads = op.spreads }
293+
case let op as CreateTemplateString:
294+
$0.createTemplateString = Fuzzilli_Protobuf_CreateTemplateString.with { $0.parts = op.parts }
293295
case let op as LoadBuiltin:
294296
$0.loadBuiltin = Fuzzilli_Protobuf_LoadBuiltin.with { $0.builtinName = op.builtinName }
295297
case let op as LoadProperty:
@@ -525,6 +527,8 @@ extension Instruction: ProtobufConvertible {
525527
op = CreateObjectWithSpread(propertyNames: p.propertyNames, numSpreads: inouts.count - 1 - p.propertyNames.count)
526528
case .createArrayWithSpread(let p):
527529
op = CreateArrayWithSpread(numInitialValues: inouts.count - 1, spreads: p.spreads)
530+
case .createTemplateString(let p):
531+
op = CreateTemplateString(parts: p.parts)
528532
case .loadBuiltin(let p):
529533
op = LoadBuiltin(builtinName: p.builtinName)
530534
case .loadProperty(let p):

Sources/Fuzzilli/FuzzIL/Operations.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,23 @@ class CreateArrayWithSpread: Operation {
240240
}
241241
}
242242

243+
class CreateTemplateString: Operation {
244+
// Stores the string elements of the temaplate literal
245+
let parts: [String]
246+
247+
var numInterpolatedValues: Int {
248+
return numInputs
249+
}
250+
251+
// This operation isn't parametric since it will most likely mutate imported templates (which would mostly be valid JS snippets) and
252+
// replace them with random strings and/or other template strings that may not be syntactically and/or semantically valid.
253+
init(parts: [String]) {
254+
self.parts = parts
255+
assert(parts.count > 0)
256+
super.init(numInputs: parts.count - 1, numOutputs: 1, attributes: [.isVarargs])
257+
}
258+
}
259+
243260
class LoadBuiltin: Operation {
244261
let builtinName: String
245262

Sources/Fuzzilli/Lifting/FuzzILLifter.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public class FuzzILLifter: Lifter {
8282
}
8383
w.emit("\(instr.output) <- CreateArrayWithSpread [\(elems.joined(separator: ", "))]")
8484

85+
case let op as CreateTemplateString:
86+
let parts = op.parts.map({ "'\($0)'" }).joined(separator: ", ")
87+
let values = instr.inputs.map({ $0.identifier }).joined(separator: ", ")
88+
w.emit("\(instr.output) <- CreateTemplateString [\(parts)], [\(values)]")
89+
8590
case let op as LoadBuiltin:
8691
w.emit("\(instr.output) <- LoadBuiltin '\(op.builtinName)'")
8792

Sources/Fuzzilli/Lifting/JavaScriptLifter.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ public class JavaScriptLifter: Lifter {
213213
}
214214
output = ArrayLiteral.new("[" + elems.joined(separator: ",") + "]")
215215

216+
case let op as CreateTemplateString:
217+
assert(!op.parts.isEmpty)
218+
assert(op.parts.count == instr.numInputs + 1)
219+
var parts = [op.parts[0]]
220+
for i in 1..<op.parts.count {
221+
parts.append("${\(input(i - 1))}\(op.parts[i])")
222+
}
223+
output = Literal.new("`" + parts.joined() + "`")
224+
216225
case let op as LoadBuiltin:
217226
output = Identifier.new(op.builtinName)
218227

Sources/Fuzzilli/Protobuf/operations.pb.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,18 @@ public struct Fuzzilli_Protobuf_CreateArray {
366366
public init() {}
367367
}
368368

369+
public struct Fuzzilli_Protobuf_CreateTemplateString {
370+
// SwiftProtobuf.Message conformance is added in an extension below. See the
371+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
372+
// methods supported on all messages.
373+
374+
public var parts: [String] = []
375+
376+
public var unknownFields = SwiftProtobuf.UnknownStorage()
377+
378+
public init() {}
379+
}
380+
369381
public struct Fuzzilli_Protobuf_CreateObjectWithSpread {
370382
// SwiftProtobuf.Message conformance is added in an extension below. See the
371383
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@@ -1693,6 +1705,38 @@ extension Fuzzilli_Protobuf_CreateArray: SwiftProtobuf.Message, SwiftProtobuf._M
16931705
}
16941706
}
16951707

1708+
extension Fuzzilli_Protobuf_CreateTemplateString: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
1709+
public static let protoMessageName: String = _protobuf_package + ".CreateTemplateString"
1710+
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1711+
1: .same(proto: "parts"),
1712+
]
1713+
1714+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
1715+
while let fieldNumber = try decoder.nextFieldNumber() {
1716+
// The use of inline closures is to circumvent an issue where the compiler
1717+
// allocates stack space for every case branch when no optimizations are
1718+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
1719+
switch fieldNumber {
1720+
case 1: try { try decoder.decodeRepeatedStringField(value: &self.parts) }()
1721+
default: break
1722+
}
1723+
}
1724+
}
1725+
1726+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
1727+
if !self.parts.isEmpty {
1728+
try visitor.visitRepeatedStringField(value: self.parts, fieldNumber: 1)
1729+
}
1730+
try unknownFields.traverse(visitor: &visitor)
1731+
}
1732+
1733+
public static func ==(lhs: Fuzzilli_Protobuf_CreateTemplateString, rhs: Fuzzilli_Protobuf_CreateTemplateString) -> Bool {
1734+
if lhs.parts != rhs.parts {return false}
1735+
if lhs.unknownFields != rhs.unknownFields {return false}
1736+
return true
1737+
}
1738+
}
1739+
16961740
extension Fuzzilli_Protobuf_CreateObjectWithSpread: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
16971741
public static let protoMessageName: String = _protobuf_package + ".CreateObjectWithSpread"
16981742
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [

Sources/Fuzzilli/Protobuf/operations.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ message CreateObject {
5555
message CreateArray {
5656
}
5757

58+
message CreateTemplateString {
59+
repeated string parts = 1;
60+
}
61+
5862
message CreateObjectWithSpread {
5963
repeated string propertyNames = 1;
6064
}

Sources/Fuzzilli/Protobuf/program.pb.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,14 @@ public struct Fuzzilli_Protobuf_Instruction {
225225
set {operation = .createArray(newValue)}
226226
}
227227

228+
public var createTemplateString: Fuzzilli_Protobuf_CreateTemplateString {
229+
get {
230+
if case .createTemplateString(let v)? = operation {return v}
231+
return Fuzzilli_Protobuf_CreateTemplateString()
232+
}
233+
set {operation = .createTemplateString(newValue)}
234+
}
235+
228236
public var createObjectWithSpread: Fuzzilli_Protobuf_CreateObjectWithSpread {
229237
get {
230238
if case .createObjectWithSpread(let v)? = operation {return v}
@@ -920,6 +928,7 @@ public struct Fuzzilli_Protobuf_Instruction {
920928
case loadRegExp(Fuzzilli_Protobuf_LoadRegExp)
921929
case createObject(Fuzzilli_Protobuf_CreateObject)
922930
case createArray(Fuzzilli_Protobuf_CreateArray)
931+
case createTemplateString(Fuzzilli_Protobuf_CreateTemplateString)
923932
case createObjectWithSpread(Fuzzilli_Protobuf_CreateObjectWithSpread)
924933
case createArrayWithSpread(Fuzzilli_Protobuf_CreateArrayWithSpread)
925934
case loadBuiltin(Fuzzilli_Protobuf_LoadBuiltin)
@@ -1056,6 +1065,10 @@ public struct Fuzzilli_Protobuf_Instruction {
10561065
guard case .createArray(let l) = lhs, case .createArray(let r) = rhs else { preconditionFailure() }
10571066
return l == r
10581067
}()
1068+
case (.createTemplateString, .createTemplateString): return {
1069+
guard case .createTemplateString(let l) = lhs, case .createTemplateString(let r) = rhs else { preconditionFailure() }
1070+
return l == r
1071+
}()
10591072
case (.createObjectWithSpread, .createObjectWithSpread): return {
10601073
guard case .createObjectWithSpread(let l) = lhs, case .createObjectWithSpread(let r) = rhs else { preconditionFailure() }
10611074
return l == r
@@ -1521,6 +1534,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M
15211534
77: .same(proto: "loadRegExp"),
15221535
11: .same(proto: "createObject"),
15231536
12: .same(proto: "createArray"),
1537+
102: .same(proto: "createTemplateString"),
15241538
13: .same(proto: "createObjectWithSpread"),
15251539
14: .same(proto: "createArrayWithSpread"),
15261540
15: .same(proto: "loadBuiltin"),
@@ -2476,6 +2490,15 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M
24762490
try decoder.decodeSingularMessageField(value: &v)
24772491
if let v = v {self.operation = .endSwitch(v)}
24782492
}()
2493+
case 102: try {
2494+
var v: Fuzzilli_Protobuf_CreateTemplateString?
2495+
if let current = self.operation {
2496+
try decoder.handleConflictingOneOf()
2497+
if case .createTemplateString(let m) = current {v = m}
2498+
}
2499+
try decoder.decodeSingularMessageField(value: &v)
2500+
if let v = v {self.operation = .createTemplateString(v)}
2501+
}()
24792502
default: break
24802503
}
24812504
}
@@ -2873,6 +2896,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M
28732896
guard case .endSwitch(let v)? = self.operation else { preconditionFailure() }
28742897
try visitor.visitSingularMessageField(value: v, fieldNumber: 101)
28752898
}()
2899+
case .createTemplateString?: try {
2900+
guard case .createTemplateString(let v)? = self.operation else { preconditionFailure() }
2901+
try visitor.visitSingularMessageField(value: v, fieldNumber: 102)
2902+
}()
28762903
case nil: break
28772904
}
28782905
try unknownFields.traverse(visitor: &visitor)

0 commit comments

Comments
 (0)