Skip to content

Commit d461c04

Browse files
authored
Add support for conditional operator (googleprojectzero#205)
1 parent f20651d commit d461c04

15 files changed

+119
-0
lines changed

Sources/Fuzzilli/Core/CodeGenerators.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ public let CodeGenerators: [CodeGenerator] = [
321321
b.compare(lhs, rhs, with: chooseUniform(from: allComparators))
322322
},
323323

324+
CodeGenerator("ConditionalOperationGenerator", inputs: (.anything, .anything)) { b, lhs, rhs in
325+
let condition = b.compare(lhs, rhs, with: chooseUniform(from: allComparators))
326+
b.conditional(condition, lhs, rhs)
327+
},
328+
324329
CodeGenerator("ClassGenerator") { b in
325330
// Possibly pick a superclass
326331
var superclass: Variable? = nil

Sources/Fuzzilli/Core/ProgramBuilder.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,11 @@ public class ProgramBuilder {
11151115
return perform(Compare(comparator), withInputs: [lhs, rhs]).output
11161116
}
11171117

1118+
@discardableResult
1119+
public func conditional(_ condition: Variable, _ lhs: Variable, _ rhs: Variable) -> Variable {
1120+
return perform(ConditionalOperation(), withInputs: [condition, lhs, rhs]).output
1121+
}
1122+
11181123
public func eval(_ string: String, with arguments: [Variable] = []) {
11191124
perform(Eval(string, numArguments: arguments.count), withInputs: arguments)
11201125
}

Sources/Fuzzilli/FuzzIL/AbstractInterpreter.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ public struct AbstractInterpreter {
349349
is CallComputedMethod:
350350
set(instr.output, .unknown)
351351

352+
case is ConditionalOperation:
353+
let outputType = state.type(of: instr.input(1)) | state.type(of: instr.input(2))
354+
set(instr.output, outputType)
355+
352356
case is CallFunction,
353357
is CallFunctionWithSpread:
354358
set(instr.output, inferCallResultType(of: instr.input(0)))

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ extension Instruction: ProtobufConvertible {
387387
$0.reassign = Fuzzilli_Protobuf_Reassign()
388388
case let op as Compare:
389389
$0.compare = Fuzzilli_Protobuf_Compare.with { $0.op = convertEnum(op.op, allComparators) }
390+
case is ConditionalOperation:
391+
$0.conditionalOperation = Fuzzilli_Protobuf_ConditionalOperation()
390392
case let op as Eval:
391393
$0.eval = Fuzzilli_Protobuf_Eval.with { $0.code = op.code }
392394
case let op as BeginClassDefinition:
@@ -613,6 +615,8 @@ extension Instruction: ProtobufConvertible {
613615
op = Reassign()
614616
case .compare(let p):
615617
op = Compare(try convertEnum(p.op, allComparators))
618+
case .conditionalOperation(_):
619+
op = ConditionalOperation()
616620
case .eval(let p):
617621
op = Eval(p.code, numArguments: inouts.count)
618622
case .beginClassDefinition(let p):

Sources/Fuzzilli/FuzzIL/Operations.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,13 @@ class Compare: Operation {
572572
}
573573
}
574574

575+
/// Allows generation of conditional (i.e. condition ? exprIfTrue : exprIfFalse) statements
576+
class ConditionalOperation: Operation {
577+
init() {
578+
super.init(numInputs: 3, numOutputs: 1)
579+
}
580+
}
581+
575582
/// An operation that will be lifted to a given string. The string can use %@ placeholders which
576583
/// will be replaced by the input variables during lowering. Eval operations will also never be mutated.
577584
class Eval: Operation {

Sources/Fuzzilli/Lifting/FuzzILLifter.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ public class FuzzILLifter: Lifter {
188188
case let op as Compare:
189189
w.emit("\(instr.output) <- Compare \(input(0)), '\(op.op.token)', \(input(1))")
190190

191+
case let op as ConditionalOperation:
192+
w.emit("\(instr.output) <- \(input(0)), \(input(1)), \(input(2))")
193+
191194
case let op as Eval:
192195
let args = instr.inputs.map({ $0.identifier }).joined(separator: ", ")
193196
w.emit("Eval '\(op.code)', [\(args)]")

Sources/Fuzzilli/Lifting/JSExpressions.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public let ArrayLiteral = ExpressionType(precedence: 17,
2525
public let PostfixExpression = ExpressionType(precedence: 16, inline: .singleUseOnly)
2626
public let UnaryExpression = ExpressionType(precedence: 15, associativity: .right, inline: .singleUseOnly)
2727
public let BinaryExpression = ExpressionType(precedence: 14, associativity: .none, inline: .singleUseOnly)
28+
public let TernaryExpression = ExpressionType(precedence: 4, associativity: .none, inline: .singleUseOnly)
2829
public let AssignmentExpression = ExpressionType(precedence: 3, inline: .never)
2930
public let ListExpression = ExpressionType(precedence: 1, associativity: .left, inline: .never)
3031

Sources/Fuzzilli/Lifting/JavaScriptLifter.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,9 @@ public class JavaScriptLifter: Lifter {
358358
case let op as Compare:
359359
output = BinaryExpression.new() <> input(0) <> " " <> op.op.token <> " " <> input(1)
360360

361+
case is ConditionalOperation:
362+
output = TernaryExpression.new() <> input(0) <> " ? " <> input(1) <> " : " <> input(2)
363+
361364
case let op as Eval:
362365
// Woraround until Strings implement the CVarArg protocol in the linux Foundation library...
363366
// TODO can make this permanent, but then use different placeholder pattern

Sources/Fuzzilli/Protobuf/operations.pb.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,16 @@ public struct Fuzzilli_Protobuf_Compare {
901901
public init() {}
902902
}
903903

904+
public struct Fuzzilli_Protobuf_ConditionalOperation {
905+
// SwiftProtobuf.Message conformance is added in an extension below. See the
906+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
907+
// methods supported on all messages.
908+
909+
public var unknownFields = SwiftProtobuf.UnknownStorage()
910+
911+
public init() {}
912+
}
913+
904914
public struct Fuzzilli_Protobuf_Eval {
905915
// SwiftProtobuf.Message conformance is added in an extension below. See the
906916
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@@ -2729,6 +2739,25 @@ extension Fuzzilli_Protobuf_Compare: SwiftProtobuf.Message, SwiftProtobuf._Messa
27292739
}
27302740
}
27312741

2742+
extension Fuzzilli_Protobuf_ConditionalOperation: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
2743+
public static let protoMessageName: String = _protobuf_package + ".ConditionalOperation"
2744+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
2745+
2746+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
2747+
while let _ = try decoder.nextFieldNumber() {
2748+
}
2749+
}
2750+
2751+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
2752+
try unknownFields.traverse(visitor: &visitor)
2753+
}
2754+
2755+
public static func ==(lhs: Fuzzilli_Protobuf_ConditionalOperation, rhs: Fuzzilli_Protobuf_ConditionalOperation) -> Bool {
2756+
if lhs.unknownFields != rhs.unknownFields {return false}
2757+
return true
2758+
}
2759+
}
2760+
27322761
extension Fuzzilli_Protobuf_Eval: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
27332762
public static let protoMessageName: String = _protobuf_package + ".Eval"
27342763
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [

Sources/Fuzzilli/Protobuf/operations.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ message Compare {
244244
Comparator op = 1;
245245
}
246246

247+
message ConditionalOperation {
248+
}
249+
247250
message Eval {
248251
string code = 1;
249252
}

0 commit comments

Comments
 (0)