From fd632f2ef9a605e4de4e8351a7a10d6256196003 Mon Sep 17 00:00:00 2001 From: Tobias Wienand Date: Wed, 20 Nov 2024 13:54:48 +0100 Subject: [PATCH 1/6] Implements compilation of for-in and for-of loop with pre-declared iterator --- Sources/Fuzzilli/Compiler/Compiler.swift | 71 +++++--- Sources/Fuzzilli/Compiler/Parser/parser.js | 26 +-- Sources/Fuzzilli/FuzzIL/Instruction.swift | 20 +- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 12 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 25 ++- Sources/Fuzzilli/FuzzIL/Semantics.swift | 4 + Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 12 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 24 ++- Sources/Fuzzilli/Protobuf/ast.pb.swift | 172 ++++++++++++++---- Sources/Fuzzilli/Protobuf/ast.proto | 18 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 42 ++++- Sources/Fuzzilli/Protobuf/operations.proto | 2 + 12 files changed, 326 insertions(+), 102 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 9e6020a41..bf8fd6460 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -412,36 +412,63 @@ public class JavaScriptCompiler { } case .forInLoop(let forInLoop): - let initializer = forInLoop.left; - guard !initializer.hasValue else { - throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop") - } - + let initializer = forInLoop.left! let obj = try compileExpression(forInLoop.right) + // Processing a for-in or for-of loop requires an iterator, which is typically declared in the function header. + // Alternatively, an existing variable can be used, resulting in an identifier instead of a variable declarator. + // If the identifier is not previously declared, it is implicitly created as a global variable. + + switch initializer { + case .variableDeclarator(let variableDeclarator): + guard !variableDeclarator.hasValue else { + throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop") + } + let loopVar = emit(BeginForInLoop(), withInputs: [obj]).innerOutput + try enterNewScope { + map(variableDeclarator.name, to: loopVar) + try compileBody(forInLoop.body) + } + emit(EndForInLoop()) - let loopVar = emit(BeginForInLoop(), withInputs: [obj]).innerOutput - try enterNewScope { - map(initializer.name, to: loopVar) - try compileBody(forInLoop.body) + case .identifier(let identifier): + guard let loopVar = lookupIdentifier(identifier.name) else { + // TODO instead of throwing an error, we should create a global property with the identifier name + throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-in loop.") + } + emit(BeginForInLoop(usesPredeclaredIterator: true), withInputs: [obj, loopVar]) + try enterNewScope { + try compileBody(forInLoop.body) + } + emit(EndForInLoop()) } - emit(EndForInLoop()) - case .forOfLoop(let forOfLoop): - let initializer = forOfLoop.left; - guard !initializer.hasValue else { - throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop") - } - + let initializer = forOfLoop.left! let obj = try compileExpression(forOfLoop.right) - let loopVar = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput - try enterNewScope { - map(initializer.name, to: loopVar) - try compileBody(forOfLoop.body) - } + switch initializer { + case .variableDeclarator(let variableDeclarator): + guard !variableDeclarator.hasValue else { + throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop") + } + let loopVar = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput + try enterNewScope { + map(variableDeclarator.name, to: loopVar) + try compileBody(forOfLoop.body) + } + emit(EndForOfLoop()) - emit(EndForOfLoop()) + case .identifier(let identifier): + guard let loopVar = lookupIdentifier(identifier.name) else { + // TODO instead of throwing an error, we should create a global property with the identifier name + throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-of loop.") + } + emit(BeginForOfLoop(usesPredeclaredIterator: true), withInputs: [obj, loopVar]) + try enterNewScope { + try compileBody(forOfLoop.body) + } + emit(EndForOfLoop()) + } case .breakStatement: // If we're in both .loop and .switch context, then the loop must be the most recent context diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 4fa1a0fbe..fc0c8662f 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -267,25 +267,27 @@ function parse(script, proto) { return makeStatement('ForLoop', forLoop); } case 'ForInStatement': { - assert(node.left.type === 'VariableDeclaration', "Expected variable declaration as init part of a for-in loop, found " + node.left.type); - assert(node.left.declarations.length === 1, "Expected exactly one variable declaration in the init part of a for-in loop"); - let decl = node.left.declarations[0]; let forInLoop = {}; - let initDecl = { name: decl.id.name }; - assert(decl.init == null, "Expected no initial value for the variable declared as part of a for-in loop") - forInLoop.left = make('VariableDeclarator', initDecl); + if (node.left.type === 'VariableDeclaration') { + assert(node.left.declarations.length === 1, "Expected exactly one variable declaration in the init part of a for-in loop"); + let decl = node.left.declarations[0]; + let initDecl = { name: decl.id.name }; + assert(decl.init == null, "Expected no initial value for the variable declared as part of a for-in loop") + forInLoop.variableDeclarator = make('VariableDeclarator', initDecl); + } else forInLoop.identifier = make('Identifier', { name: node.left.name }); forInLoop.right = visitExpression(node.right); forInLoop.body = visitStatement(node.body); return makeStatement('ForInLoop', forInLoop); } case 'ForOfStatement': { - assert(node.left.type === 'VariableDeclaration', "Expected variable declaration as init part of a for-in loop, found " + node.left.type); - assert(node.left.declarations.length === 1, "Expected exactly one variable declaration in the init part of a for-in loop"); - let decl = node.left.declarations[0]; let forOfLoop = {}; - let initDecl = { name: decl.id.name }; - assert(decl.init == null, "Expected no initial value for the variable declared as part of a for-in loop") - forOfLoop.left = make('VariableDeclarator', initDecl); + if (node.left.type === 'VariableDeclaration') { + assert(node.left.declarations.length === 1, "Expected exactly one variable declaration in the init part of a for-of loop"); + let decl = node.left.declarations[0]; + let initDecl = { name: decl.id.name }; + assert(decl.init == null, "Expected no initial value for the variable declared as part of a for-of loop") + forOfLoop.variableDeclarator = make('VariableDeclarator', initDecl); + } else forOfLoop.identifier = make('Identifier', { name: node.left.name }); forOfLoop.right = visitExpression(node.right); forOfLoop.body = visitStatement(node.body); return makeStatement('ForOfLoop', forOfLoop); diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index d770196b2..cc6c2e38c 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -790,12 +790,16 @@ extension Instruction: ProtobufConvertible { $0.beginForLoopBody = Fuzzilli_Protobuf_BeginForLoopBody() case .endForLoop: $0.endForLoop = Fuzzilli_Protobuf_EndForLoop() - case .beginForInLoop: - $0.beginForInLoop = Fuzzilli_Protobuf_BeginForInLoop() + case .beginForInLoop(let op): + $0.beginForInLoop = Fuzzilli_Protobuf_BeginForInLoop.with { protobufOp in + protobufOp.usesPredeclaredIterator = op.usesPredeclaredIterator + } case .endForInLoop: $0.endForInLoop = Fuzzilli_Protobuf_EndForInLoop() - case .beginForOfLoop: - $0.beginForOfLoop = Fuzzilli_Protobuf_BeginForOfLoop() + case .beginForOfLoop(let op): + $0.beginForOfLoop = Fuzzilli_Protobuf_BeginForOfLoop.with { protobufOp in + protobufOp.usesPredeclaredIterator = op.usesPredeclaredIterator + } case .beginForOfLoopWithDestruct(let op): $0.beginForOfLoopWithDestruct = Fuzzilli_Protobuf_BeginForOfLoopWithDestruct.with { $0.indices = op.indices.map({ Int32($0) }) @@ -1212,12 +1216,12 @@ extension Instruction: ProtobufConvertible { op = BeginForLoopBody(numLoopVariables: inouts.count) case .endForLoop: op = EndForLoop() - case .beginForInLoop: - op = BeginForInLoop() + case .beginForInLoop(let p): + op = BeginForInLoop(usesPredeclaredIterator: p.usesPredeclaredIterator) case .endForInLoop: op = EndForInLoop() - case .beginForOfLoop: - op = BeginForOfLoop() + case .beginForOfLoop(let p): + op = BeginForOfLoop(usesPredeclaredIterator: p.usesPredeclaredIterator) case .beginForOfLoopWithDestruct(let p): op = BeginForOfLoopWithDestruct(indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p) case .endForOfLoop: diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index dc9858454..11e977ff7 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -794,10 +794,18 @@ public struct JSTyper: Analyzer { zip(instr.innerOutputs, inputTypes).forEach({ set($0, $1) }) case .beginForInLoop: - set(instr.innerOutput, .string) + if instr.numInputs == 2 { + set(instr.input(1), .string) // Iterator is declared beforehand + } else { + set(instr.innerOutput, .string) // Iterator is declared in the function header + } case .beginForOfLoop: - set(instr.innerOutput, .anything) + if instr.numInputs == 2 { + set(instr.input(1), .anything) + } else { + set(instr.innerOutput, .anything) + } case .beginForOfLoopWithDestruct: for v in instr.innerOutputs { diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index bab2bd749..41db5cbdf 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1967,8 +1967,16 @@ final class EndForLoop: JsOperation { final class BeginForInLoop: JsOperation { override var opcode: Opcode { .beginForInLoop(self) } - init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + let usesPredeclaredIterator: Bool + + init(usesPredeclaredIterator: Bool = false) { + self.usesPredeclaredIterator = usesPredeclaredIterator + super.init( + numInputs: usesPredeclaredIterator ? 2 : 1, + numInnerOutputs: usesPredeclaredIterator ? 0 : 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop] + ) } } @@ -1983,8 +1991,17 @@ final class EndForInLoop: JsOperation { final class BeginForOfLoop: JsOperation { override var opcode: Opcode { .beginForOfLoop(self) } - init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + + let usesPredeclaredIterator: Bool + + init(usesPredeclaredIterator: Bool = false) { + self.usesPredeclaredIterator = usesPredeclaredIterator + super.init( + numInputs: usesPredeclaredIterator ? 2 : 1, + numInnerOutputs: usesPredeclaredIterator ? 0 : 1, + attributes: [.isBlockStart, .propagatesSurroundingContext], + contextOpened: [.javascript, .loop] + ) } } diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index e8110e02c..b58b16483 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -54,6 +54,10 @@ extension Operation { case .destructArrayAndReassign, .destructObjectAndReassign: return inputIdx != 0 + case .beginForInLoop(let op): + return op.usesPredeclaredIterator && inputIdx == 1 + case .beginForOfLoop(let op): + return op.usesPredeclaredIterator && inputIdx == 1 default: return false } diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index aa489854b..9e675c050 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -667,7 +667,11 @@ public class FuzzILLifter: Lifter { w.emit("EndForLoop") case .beginForInLoop: - w.emit("BeginForInLoop \(input(0)) -> \(innerOutput())") + if instr.numInputs == 2 { + w.emit("BeginForInLoop \(input(0)) -> \(input(1))") // Iterator is declared beforehand + } else { + w.emit("BeginForInLoop \(input(0)) -> \(innerOutput())") // Iterator is declared in the function header + } w.increaseIndentionLevel() case .endForInLoop: @@ -675,7 +679,11 @@ public class FuzzILLifter: Lifter { w.emit("EndForInLoop") case .beginForOfLoop: - w.emit("BeginForOfLoop \(input(0)) -> \(innerOutput())") + if instr.numInputs == 2 { + w.emit("BeginForOfLoop \(input(0)) -> \(input(1))") + } else { + w.emit("BeginForOfLoop \(input(0)) -> \(innerOutput())") + } w.increaseIndentionLevel() case .beginForOfLoopWithDestruct(let op): diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 240f3ea99..08027a20c 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1169,10 +1169,16 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .beginForInLoop: - let LET = w.declarationKeyword(for: instr.innerOutput) - let V = w.declare(instr.innerOutput) let OBJ = input(0) - w.emit("for (\(LET) \(V) in \(OBJ)) {") + let LET: String = "" + if instr.numInputs == 2 { // Iterator is declared elsewhere + let V = input(1) + w.emit("for (\(LET) \(V) in \(OBJ)) {") + } else { // Iterator is declared in the function header + let V = w.declare(instr.innerOutput) + let LET = w.declarationKeyword(for: instr.innerOutput) + w.emit("for (\(LET) \(V) in \(OBJ)) {") + } w.enterNewBlock() case .endForInLoop: @@ -1180,10 +1186,16 @@ public class JavaScriptLifter: Lifter { w.emit("}") case .beginForOfLoop: - let V = w.declare(instr.innerOutput) - let LET = w.declarationKeyword(for: instr.innerOutput) let OBJ = input(0) - w.emit("for (\(LET) \(V) of \(OBJ)) {") + let LET: String = "" + if instr.numInputs == 2 { + let V = input(1) + w.emit("for (\(LET) \(V) of \(OBJ)) {") + } else { + let V = w.declare(instr.innerOutput) + let LET = w.declarationKeyword(for: instr.innerOutput) + w.emit("for (\(LET) \(V) of \(OBJ)) {") + } w.enterNewBlock() case .beginForOfLoopWithDestruct(let op): diff --git a/Sources/Fuzzilli/Protobuf/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index 60d2eb9c5..ea3dd8651 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -690,14 +690,26 @@ public struct Compiler_Protobuf_ForInLoop: @unchecked Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var left: Compiler_Protobuf_VariableDeclarator { - get {return _storage._left ?? Compiler_Protobuf_VariableDeclarator()} + public var left: OneOf_Left? { + get {return _storage._left} set {_uniqueStorage()._left = newValue} } - /// Returns true if `left` has been explicitly set. - public var hasLeft: Bool {return _storage._left != nil} - /// Clears the value of `left`. Subsequent reads from it will return its default value. - public mutating func clearLeft() {_uniqueStorage()._left = nil} + + public var variableDeclarator: Compiler_Protobuf_VariableDeclarator { + get { + if case .variableDeclarator(let v)? = _storage._left {return v} + return Compiler_Protobuf_VariableDeclarator() + } + set {_uniqueStorage()._left = .variableDeclarator(newValue)} + } + + public var identifier: Compiler_Protobuf_Identifier { + get { + if case .identifier(let v)? = _storage._left {return v} + return Compiler_Protobuf_Identifier() + } + set {_uniqueStorage()._left = .identifier(newValue)} + } public var right: Compiler_Protobuf_Expression { get {return _storage._right ?? Compiler_Protobuf_Expression()} @@ -719,6 +731,12 @@ public struct Compiler_Protobuf_ForInLoop: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() + public enum OneOf_Left: Equatable, Sendable { + case variableDeclarator(Compiler_Protobuf_VariableDeclarator) + case identifier(Compiler_Protobuf_Identifier) + + } + public init() {} fileprivate var _storage = _StorageClass.defaultInstance @@ -729,14 +747,26 @@ public struct Compiler_Protobuf_ForOfLoop: @unchecked Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var left: Compiler_Protobuf_VariableDeclarator { - get {return _storage._left ?? Compiler_Protobuf_VariableDeclarator()} + public var left: OneOf_Left? { + get {return _storage._left} set {_uniqueStorage()._left = newValue} } - /// Returns true if `left` has been explicitly set. - public var hasLeft: Bool {return _storage._left != nil} - /// Clears the value of `left`. Subsequent reads from it will return its default value. - public mutating func clearLeft() {_uniqueStorage()._left = nil} + + public var variableDeclarator: Compiler_Protobuf_VariableDeclarator { + get { + if case .variableDeclarator(let v)? = _storage._left {return v} + return Compiler_Protobuf_VariableDeclarator() + } + set {_uniqueStorage()._left = .variableDeclarator(newValue)} + } + + public var identifier: Compiler_Protobuf_Identifier { + get { + if case .identifier(let v)? = _storage._left {return v} + return Compiler_Protobuf_Identifier() + } + set {_uniqueStorage()._left = .identifier(newValue)} + } public var right: Compiler_Protobuf_Expression { get {return _storage._right ?? Compiler_Protobuf_Expression()} @@ -758,6 +788,12 @@ public struct Compiler_Protobuf_ForOfLoop: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() + public enum OneOf_Left: Equatable, Sendable { + case variableDeclarator(Compiler_Protobuf_VariableDeclarator) + case identifier(Compiler_Protobuf_Identifier) + + } + public init() {} fileprivate var _storage = _StorageClass.defaultInstance @@ -3576,13 +3612,14 @@ extension Compiler_Protobuf_ForLoop: SwiftProtobuf.Message, SwiftProtobuf._Messa extension Compiler_Protobuf_ForInLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ForInLoop" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "left"), - 2: .same(proto: "right"), - 3: .same(proto: "body"), + 1: .same(proto: "variableDeclarator"), + 2: .same(proto: "identifier"), + 3: .same(proto: "right"), + 4: .same(proto: "body"), ] fileprivate class _StorageClass { - var _left: Compiler_Protobuf_VariableDeclarator? = nil + var _left: Compiler_Protobuf_ForInLoop.OneOf_Left? var _right: Compiler_Protobuf_Expression? = nil var _body: Compiler_Protobuf_Statement? = nil @@ -3620,9 +3657,34 @@ extension Compiler_Protobuf_ForInLoop: SwiftProtobuf.Message, SwiftProtobuf._Mes // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &_storage._left) }() - case 2: try { try decoder.decodeSingularMessageField(value: &_storage._right) }() - case 3: try { try decoder.decodeSingularMessageField(value: &_storage._body) }() + case 1: try { + var v: Compiler_Protobuf_VariableDeclarator? + var hadOneofValue = false + if let current = _storage._left { + hadOneofValue = true + if case .variableDeclarator(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._left = .variableDeclarator(v) + } + }() + case 2: try { + var v: Compiler_Protobuf_Identifier? + var hadOneofValue = false + if let current = _storage._left { + hadOneofValue = true + if case .identifier(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._left = .identifier(v) + } + }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._right) }() + case 4: try { try decoder.decodeSingularMessageField(value: &_storage._body) }() default: break } } @@ -3635,14 +3697,22 @@ extension Compiler_Protobuf_ForInLoop: SwiftProtobuf.Message, SwiftProtobuf._Mes // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = _storage._left { + switch _storage._left { + case .variableDeclarator?: try { + guard case .variableDeclarator(let v)? = _storage._left else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - try { if let v = _storage._right { + }() + case .identifier?: try { + guard case .identifier(let v)? = _storage._left else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + }() + case nil: break + } + try { if let v = _storage._right { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() try { if let v = _storage._body { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) } }() } try unknownFields.traverse(visitor: &visitor) @@ -3668,13 +3738,14 @@ extension Compiler_Protobuf_ForInLoop: SwiftProtobuf.Message, SwiftProtobuf._Mes extension Compiler_Protobuf_ForOfLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".ForOfLoop" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "left"), - 2: .same(proto: "right"), - 3: .same(proto: "body"), + 1: .same(proto: "variableDeclarator"), + 2: .same(proto: "identifier"), + 3: .same(proto: "right"), + 4: .same(proto: "body"), ] fileprivate class _StorageClass { - var _left: Compiler_Protobuf_VariableDeclarator? = nil + var _left: Compiler_Protobuf_ForOfLoop.OneOf_Left? var _right: Compiler_Protobuf_Expression? = nil var _body: Compiler_Protobuf_Statement? = nil @@ -3712,9 +3783,34 @@ extension Compiler_Protobuf_ForOfLoop: SwiftProtobuf.Message, SwiftProtobuf._Mes // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &_storage._left) }() - case 2: try { try decoder.decodeSingularMessageField(value: &_storage._right) }() - case 3: try { try decoder.decodeSingularMessageField(value: &_storage._body) }() + case 1: try { + var v: Compiler_Protobuf_VariableDeclarator? + var hadOneofValue = false + if let current = _storage._left { + hadOneofValue = true + if case .variableDeclarator(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._left = .variableDeclarator(v) + } + }() + case 2: try { + var v: Compiler_Protobuf_Identifier? + var hadOneofValue = false + if let current = _storage._left { + hadOneofValue = true + if case .identifier(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._left = .identifier(v) + } + }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._right) }() + case 4: try { try decoder.decodeSingularMessageField(value: &_storage._body) }() default: break } } @@ -3727,14 +3823,22 @@ extension Compiler_Protobuf_ForOfLoop: SwiftProtobuf.Message, SwiftProtobuf._Mes // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = _storage._left { + switch _storage._left { + case .variableDeclarator?: try { + guard case .variableDeclarator(let v)? = _storage._left else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - try { if let v = _storage._right { + }() + case .identifier?: try { + guard case .identifier(let v)? = _storage._left else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + }() + case nil: break + } + try { if let v = _storage._right { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() try { if let v = _storage._body { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) } }() } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/ast.proto b/Sources/Fuzzilli/Protobuf/ast.proto index 3db9a50c4..5e980ca76 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -163,15 +163,21 @@ message ForLoop { } message ForInLoop { - VariableDeclarator left = 1; - Expression right = 2; - Statement body = 3; + oneof left { + VariableDeclarator variableDeclarator = 1; + Identifier identifier = 2; + } + Expression right = 3; + Statement body = 4; } message ForOfLoop { - VariableDeclarator left = 1; - Expression right = 2; - Statement body = 3; + oneof left { + VariableDeclarator variableDeclarator = 1; + Identifier identifier = 2; + } + Expression right = 3; + Statement body = 4; } message BreakStatement { diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 5bb356cdc..27e86e3f0 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -2274,6 +2274,8 @@ public struct Fuzzilli_Protobuf_BeginForInLoop: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. + public var usesPredeclaredIterator: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -2294,6 +2296,8 @@ public struct Fuzzilli_Protobuf_BeginForOfLoop: Sendable { // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. + public var usesPredeclaredIterator: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -7106,18 +7110,31 @@ extension Fuzzilli_Protobuf_EndForLoop: SwiftProtobuf.Message, SwiftProtobuf._Me extension Fuzzilli_Protobuf_BeginForInLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginForInLoop" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "usesPredeclaredIterator"), + ] public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &self.usesPredeclaredIterator) }() + default: break + } + } } public func traverse(visitor: inout V) throws { + if self.usesPredeclaredIterator != false { + try visitor.visitSingularBoolField(value: self.usesPredeclaredIterator, fieldNumber: 1) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_BeginForInLoop, rhs: Fuzzilli_Protobuf_BeginForInLoop) -> Bool { + if lhs.usesPredeclaredIterator != rhs.usesPredeclaredIterator {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -7144,18 +7161,31 @@ extension Fuzzilli_Protobuf_EndForInLoop: SwiftProtobuf.Message, SwiftProtobuf._ extension Fuzzilli_Protobuf_BeginForOfLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginForOfLoop" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "usesPredeclaredIterator"), + ] public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &self.usesPredeclaredIterator) }() + default: break + } + } } public func traverse(visitor: inout V) throws { + if self.usesPredeclaredIterator != false { + try visitor.visitSingularBoolField(value: self.usesPredeclaredIterator, fieldNumber: 1) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Fuzzilli_Protobuf_BeginForOfLoop, rhs: Fuzzilli_Protobuf_BeginForOfLoop) -> Bool { + if lhs.usesPredeclaredIterator != rhs.usesPredeclaredIterator {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 524e45a83..09d1519a4 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -681,12 +681,14 @@ message EndForLoop { } message BeginForInLoop { + bool usesPredeclaredIterator = 1; } message EndForInLoop { } message BeginForOfLoop { + bool usesPredeclaredIterator = 1; } message BeginForOfLoopWithDestruct { From 554580263c46685c56908d82cc968fadc246a5d4 Mon Sep 17 00:00:00 2001 From: Tobias Wienand Date: Thu, 5 Dec 2024 21:20:17 +0100 Subject: [PATCH 2/6] Refactor for-in and for-of loop iteration in JavaScriptLifter.swift --- Sources/Fuzzilli/Lifting/JavaScriptLifter.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 08027a20c..fb72d3388 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1170,10 +1170,9 @@ public class JavaScriptLifter: Lifter { case .beginForInLoop: let OBJ = input(0) - let LET: String = "" if instr.numInputs == 2 { // Iterator is declared elsewhere let V = input(1) - w.emit("for (\(LET) \(V) in \(OBJ)) {") + w.emit("for (\(V) in \(OBJ)) {") } else { // Iterator is declared in the function header let V = w.declare(instr.innerOutput) let LET = w.declarationKeyword(for: instr.innerOutput) @@ -1187,10 +1186,9 @@ public class JavaScriptLifter: Lifter { case .beginForOfLoop: let OBJ = input(0) - let LET: String = "" if instr.numInputs == 2 { let V = input(1) - w.emit("for (\(LET) \(V) of \(OBJ)) {") + w.emit("for (\(V) of \(OBJ)) {") } else { let V = w.declare(instr.innerOutput) let LET = w.declarationKeyword(for: instr.innerOutput) From 434d594f87ba6a1e0818f0d6f8b56de7a8e5eb80 Mon Sep 17 00:00:00 2001 From: Tobias Wienand Date: Sat, 7 Dec 2024 13:09:58 +0100 Subject: [PATCH 3/6] Refactor of for-in and for-of loops. Makes each type of loop a seperate instruction in FuzzIL --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 22 +- .../CodeGen/CodeGeneratorWeights.swift | 6 +- Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 25 +- Sources/Fuzzilli/Compiler/Compiler.swift | 8 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 33 ++- Sources/Fuzzilli/FuzzIL/JSTyper.swift | 28 +- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 45 ++- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 6 +- Sources/Fuzzilli/FuzzIL/Semantics.swift | 14 +- Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 24 +- .../Fuzzilli/Lifting/JavaScriptLifter.swift | 38 +-- .../Fuzzilli/Minimization/BlockReducer.swift | 6 +- .../Fuzzilli/Minimization/LoopReducer.swift | 8 +- Sources/Fuzzilli/Protobuf/operations.pb.swift | 112 +++++--- Sources/Fuzzilli/Protobuf/operations.proto | 12 +- Sources/Fuzzilli/Protobuf/program.pb.swift | 262 +++++++++++------- Sources/Fuzzilli/Protobuf/program.proto | 60 ++-- Tests/FuzzilliTests/AnalyzerTest.swift | 15 +- Tests/FuzzilliTests/JSTyperTests.swift | 4 +- Tests/FuzzilliTests/LifterTest.swift | 33 ++- Tests/FuzzilliTests/ProgramBuilderTest.swift | 4 +- 21 files changed, 465 insertions(+), 300 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 3eb4cb968..c85d0137e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2488,19 +2488,31 @@ public class ProgramBuilder { emit(EndForLoop()) } - public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> ()) { - let i = emit(BeginForInLoop(), withInputs: [obj]).innerOutput + public func buildPlainForInLoop(_ obj: Variable, _ body: (Variable) -> ()) { + let i = emit(BeginPlainForInLoop(), withInputs: [obj]).innerOutput body(i) emit(EndForInLoop()) } - public func buildForOfLoop(_ obj: Variable, _ body: (Variable) -> ()) { - let i = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput + public func buildForInLoopWithReassignment(_ obj: Variable, _ existingVar: Variable, _ body: () -> ()) { + emit(BeginForInLoopWithReassignment(), withInputs: [obj, existingVar]) + body() + emit(EndForInLoop()) + } + + public func buildPlainForOfLoop(_ obj: Variable, _ body: (Variable) -> ()) { + let i = emit(BeginPlainForOfLoop(), withInputs: [obj]).innerOutput body(i) emit(EndForOfLoop()) } - public func buildForOfLoop(_ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, _ body: ([Variable]) -> ()) { + public func buildForOfLoopWithReassignment(_ obj: Variable, _ existingVar: Variable, _ body: () -> ()) { + emit(BeginForOfLoopWithReassignment(), withInputs: [obj, existingVar]) + body() + emit(EndForOfLoop()) + } + + public func buildForOfLoopWithDestruct(_ obj: Variable, selecting indices: [Int64], hasRestElement: Bool = false, _ body: ([Variable]) -> ()) { let instr = emit(BeginForOfLoopWithDestruct(indices: indices, hasRestElement: hasRestElement), withInputs: [obj]) body(Array(instr.innerOutputs)) emit(EndForOfLoop()) diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index bda9a0d7b..74ab0dfc6 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -158,8 +158,10 @@ public let codeGeneratorWeights = [ "DoWhileLoopGenerator": 15, "SimpleForLoopGenerator": 10, "ComplexForLoopGenerator": 10, - "ForInLoopGenerator": 10, - "ForOfLoopGenerator": 10, + "PlainForInLoopGenerator": 8, + "ForInLoopWithReassignmentGenerator": 2, + "PlainForOfLoopGenerator": 8, + "ForOfLoopWithReassignmentGenerator": 2, "ForOfWithDestructLoopGenerator": 3, "RepeatLoopGenerator": 10, "SwitchCaseBreakGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 616106d93..9eb704cb5 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1366,14 +1366,29 @@ public let CodeGenerators: [CodeGenerator] = [ } }, - RecursiveCodeGenerator("ForInLoopGenerator", inputs: .preferred(.object())) { b, obj in - b.buildForInLoop(obj) { _ in + RecursiveCodeGenerator("PlainForInLoopGenerator", inputs: .preferred(.object())) { b, obj in + b.buildPlainForInLoop(obj) { _ in b.buildRecursive() } }, - RecursiveCodeGenerator("ForOfLoopGenerator", inputs: .preferred(.iterable)) { b, obj in - b.buildForOfLoop(obj) { _ in + RecursiveCodeGenerator("ForInLoopWithReassignmentGenerator", inputs: .preferred(.object())) { b, obj in + // use a pre-declared variable as the iterator variable (i.e., reassign it) + let existing = b.randomVariable() + b.buildForInLoopWithReassignment(obj, existing) { + b.buildRecursive() + } + }, + + RecursiveCodeGenerator("PlainForOfLoopGenerator", inputs: .preferred(.iterable)) { b, obj in + b.buildPlainForOfLoop(obj) { _ in + b.buildRecursive() + } + }, + + RecursiveCodeGenerator("ForOfLoopWithReassignmentGenerator", inputs: .preferred(.iterable)) { b, obj in + let existing = b.randomVariable() + b.buildForOfLoopWithReassignment(obj, existing) { b.buildRecursive() } }, @@ -1390,7 +1405,7 @@ public let CodeGenerators: [CodeGenerator] = [ indices = [0] } - b.buildForOfLoop(obj, selecting: indices, hasRestElement: probability(0.2)) { _ in + b.buildForOfLoopWithDestruct(obj, selecting: indices, hasRestElement: probability(0.2)) { _ in b.buildRecursive() } }, diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index 9e9da8b6e..fcb6f4a1a 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -423,7 +423,7 @@ public class JavaScriptCompiler { guard !variableDeclarator.hasValue else { throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop") } - let loopVar = emit(BeginForInLoop(), withInputs: [obj]).innerOutput + let loopVar = emit(BeginPlainForInLoop(), withInputs: [obj]).innerOutput try enterNewScope { map(variableDeclarator.name, to: loopVar) try compileBody(forInLoop.body) @@ -435,7 +435,7 @@ public class JavaScriptCompiler { // TODO instead of throwing an error, we should create a global property with the identifier name throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-in loop.") } - emit(BeginForInLoop(usesPredeclaredIterator: true), withInputs: [obj, loopVar]) + emit(BeginForInLoopWithReassignment(), withInputs: [obj, loopVar]) try enterNewScope { try compileBody(forInLoop.body) } @@ -451,7 +451,7 @@ public class JavaScriptCompiler { guard !variableDeclarator.hasValue else { throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop") } - let loopVar = emit(BeginForOfLoop(), withInputs: [obj]).innerOutput + let loopVar = emit(BeginPlainForOfLoop(), withInputs: [obj]).innerOutput try enterNewScope { map(variableDeclarator.name, to: loopVar) try compileBody(forOfLoop.body) @@ -463,7 +463,7 @@ public class JavaScriptCompiler { // TODO instead of throwing an error, we should create a global property with the identifier name throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-of loop.") } - emit(BeginForOfLoop(usesPredeclaredIterator: true), withInputs: [obj, loopVar]) + emit(BeginForOfLoopWithReassignment(), withInputs: [obj, loopVar]) try enterNewScope { try compileBody(forOfLoop.body) } diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index cc6c2e38c..a7a1e88a5 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -790,16 +790,16 @@ extension Instruction: ProtobufConvertible { $0.beginForLoopBody = Fuzzilli_Protobuf_BeginForLoopBody() case .endForLoop: $0.endForLoop = Fuzzilli_Protobuf_EndForLoop() - case .beginForInLoop(let op): - $0.beginForInLoop = Fuzzilli_Protobuf_BeginForInLoop.with { protobufOp in - protobufOp.usesPredeclaredIterator = op.usesPredeclaredIterator - } + case .beginPlainForInLoop: + $0.beginPlainForInLoop = Fuzzilli_Protobuf_BeginPlainForInLoop() + case .beginForInLoopWithReassignment: + $0.beginForInLoopWithReassignment = Fuzzilli_Protobuf_BeginForInLoopWithReassignment() case .endForInLoop: $0.endForInLoop = Fuzzilli_Protobuf_EndForInLoop() - case .beginForOfLoop(let op): - $0.beginForOfLoop = Fuzzilli_Protobuf_BeginForOfLoop.with { protobufOp in - protobufOp.usesPredeclaredIterator = op.usesPredeclaredIterator - } + case .beginPlainForOfLoop: + $0.beginPlainForOfLoop = Fuzzilli_Protobuf_BeginPlainForOfLoop() + case .beginForOfLoopWithReassignment: + $0.beginForOfLoopWithReassignment = Fuzzilli_Protobuf_BeginForOfLoopWithReassignment() case .beginForOfLoopWithDestruct(let op): $0.beginForOfLoopWithDestruct = Fuzzilli_Protobuf_BeginForOfLoopWithDestruct.with { $0.indices = op.indices.map({ Int32($0) }) @@ -1216,14 +1216,21 @@ extension Instruction: ProtobufConvertible { op = BeginForLoopBody(numLoopVariables: inouts.count) case .endForLoop: op = EndForLoop() - case .beginForInLoop(let p): - op = BeginForInLoop(usesPredeclaredIterator: p.usesPredeclaredIterator) + case .beginPlainForInLoop: + op = BeginPlainForInLoop() + case .beginForInLoopWithReassignment: + op = BeginForInLoopWithReassignment() case .endForInLoop: op = EndForInLoop() - case .beginForOfLoop(let p): - op = BeginForOfLoop(usesPredeclaredIterator: p.usesPredeclaredIterator) + case .beginPlainForOfLoop: + op = BeginPlainForOfLoop() + case .beginForOfLoopWithReassignment: + op = BeginForOfLoopWithReassignment() case .beginForOfLoopWithDestruct(let p): - op = BeginForOfLoopWithDestruct(indices: p.indices.map({ Int64($0) }), hasRestElement: p.hasRestElement_p) + op = BeginForOfLoopWithDestruct( + indices: p.indices.map({ Int64($0) }), + hasRestElement: p.hasRestElement_p + ) case .endForOfLoop: op = EndForOfLoop() case .beginRepeatLoop(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JSTyper.swift b/Sources/Fuzzilli/FuzzIL/JSTyper.swift index 11e977ff7..9ed986a97 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -283,8 +283,10 @@ public struct JSTyper: Analyzer { case .endForLoop: state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges) case .beginWhileLoopBody, - .beginForInLoop, - .beginForOfLoop, + .beginPlainForInLoop, + .beginForInLoopWithReassignment, + .beginPlainForOfLoop, + .beginForOfLoopWithReassignment, .beginForOfLoopWithDestruct, .beginRepeatLoop, .beginCodeString: @@ -793,19 +795,17 @@ public struct JSTyper: Analyzer { assert(inputTypes.count == instr.numInnerOutputs) zip(instr.innerOutputs, inputTypes).forEach({ set($0, $1) }) - case .beginForInLoop: - if instr.numInputs == 2 { - set(instr.input(1), .string) // Iterator is declared beforehand - } else { - set(instr.innerOutput, .string) // Iterator is declared in the function header - } + case .beginPlainForInLoop: + set(instr.innerOutput, .string) - case .beginForOfLoop: - if instr.numInputs == 2 { - set(instr.input(1), .anything) - } else { - set(instr.innerOutput, .anything) - } + case .beginForInLoopWithReassignment: + set(instr.input(1), .string) + + case .beginPlainForOfLoop: + set(instr.innerOutput, .anything) + + case .beginForOfLoopWithReassignment: + set(instr.input(1), .anything) case .beginForOfLoopWithDestruct: for v in instr.innerOutputs { diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 41db5cbdf..e4b3b1d57 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1964,19 +1964,17 @@ final class EndForLoop: JsOperation { } } -final class BeginForInLoop: JsOperation { - override var opcode: Opcode { .beginForInLoop(self) } - - let usesPredeclaredIterator: Bool +final class BeginPlainForInLoop: JsOperation { + override var opcode: Opcode { .beginPlainForInLoop(self) } + init() { + super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + } +} - init(usesPredeclaredIterator: Bool = false) { - self.usesPredeclaredIterator = usesPredeclaredIterator - super.init( - numInputs: usesPredeclaredIterator ? 2 : 1, - numInnerOutputs: usesPredeclaredIterator ? 0 : 1, - attributes: [.isBlockStart, .propagatesSurroundingContext], - contextOpened: [.javascript, .loop] - ) +final class BeginForInLoopWithReassignment: JsOperation { + override var opcode: Opcode { .beginForInLoopWithReassignment(self) } + init() { + super.init(numInputs: 2, numInnerOutputs: 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } } @@ -1988,20 +1986,17 @@ final class EndForInLoop: JsOperation { } } -final class BeginForOfLoop: JsOperation { - override var opcode: Opcode { .beginForOfLoop(self) } - - - let usesPredeclaredIterator: Bool +final class BeginPlainForOfLoop: JsOperation { + override var opcode: Opcode { .beginPlainForOfLoop(self) } + init() { + super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + } +} - init(usesPredeclaredIterator: Bool = false) { - self.usesPredeclaredIterator = usesPredeclaredIterator - super.init( - numInputs: usesPredeclaredIterator ? 2 : 1, - numInnerOutputs: usesPredeclaredIterator ? 0 : 1, - attributes: [.isBlockStart, .propagatesSurroundingContext], - contextOpened: [.javascript, .loop] - ) +final class BeginForOfLoopWithReassignment: JsOperation { + override var opcode: Opcode { .beginForOfLoopWithReassignment(self) } + init() { + super.init(numInputs: 2, numInnerOutputs: 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } } diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index e0b9f37fa..a2b9817a0 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -176,9 +176,11 @@ enum Opcode { case beginForLoopAfterthought(BeginForLoopAfterthought) case beginForLoopBody(BeginForLoopBody) case endForLoop(EndForLoop) - case beginForInLoop(BeginForInLoop) + case beginPlainForInLoop(BeginPlainForInLoop) + case beginForInLoopWithReassignment(BeginForInLoopWithReassignment) case endForInLoop(EndForInLoop) - case beginForOfLoop(BeginForOfLoop) + case beginPlainForOfLoop(BeginPlainForOfLoop) + case beginForOfLoopWithReassignment(BeginForOfLoopWithReassignment) case beginForOfLoopWithDestruct(BeginForOfLoopWithDestruct) case endForOfLoop(EndForOfLoop) case beginRepeatLoop(BeginRepeatLoop) diff --git a/Sources/Fuzzilli/FuzzIL/Semantics.swift b/Sources/Fuzzilli/FuzzIL/Semantics.swift index b58b16483..e869ee00f 100644 --- a/Sources/Fuzzilli/FuzzIL/Semantics.swift +++ b/Sources/Fuzzilli/FuzzIL/Semantics.swift @@ -54,10 +54,10 @@ extension Operation { case .destructArrayAndReassign, .destructObjectAndReassign: return inputIdx != 0 - case .beginForInLoop(let op): - return op.usesPredeclaredIterator && inputIdx == 1 - case .beginForOfLoop(let op): - return op.usesPredeclaredIterator && inputIdx == 1 + case .beginForInLoopWithReassignment: + return inputIdx == 1 + case .beginForOfLoopWithReassignment: + return inputIdx == 1 default: return false } @@ -210,9 +210,11 @@ extension Operation { return endOp is BeginForLoopBody case .beginForLoopBody: return endOp is EndForLoop - case .beginForInLoop: + case .beginPlainForInLoop, + .beginForInLoopWithReassignment: return endOp is EndForInLoop - case .beginForOfLoop, + case .beginPlainForOfLoop, + .beginForOfLoopWithReassignment, .beginForOfLoopWithDestruct: return endOp is EndForOfLoop case .beginRepeatLoop: diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 9e675c050..84edec2b4 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -666,24 +666,24 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndForLoop") - case .beginForInLoop: - if instr.numInputs == 2 { - w.emit("BeginForInLoop \(input(0)) -> \(input(1))") // Iterator is declared beforehand - } else { - w.emit("BeginForInLoop \(input(0)) -> \(innerOutput())") // Iterator is declared in the function header - } + case .beginPlainForInLoop: + w.emit("BeginPlainForInLoop \(input(0)) -> \(innerOutput())") + w.increaseIndentionLevel() + + case .beginForInLoopWithReassignment: + w.emit("BeginForInLoopWithReassignment \(input(0)) -> \(input(1))") w.increaseIndentionLevel() case .endForInLoop: w.decreaseIndentionLevel() w.emit("EndForInLoop") - case .beginForOfLoop: - if instr.numInputs == 2 { - w.emit("BeginForOfLoop \(input(0)) -> \(input(1))") - } else { - w.emit("BeginForOfLoop \(input(0)) -> \(innerOutput())") - } + case .beginPlainForOfLoop: + w.emit("BeginPlainForOfLoop \(input(0)) -> \(innerOutput())") + w.increaseIndentionLevel() + + case .beginForOfLoopWithReassignment: + w.emit("BeginForOfLoopWithReassignment \(input(0)) -> \(input(1))") w.increaseIndentionLevel() case .beginForOfLoopWithDestruct(let op): diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index fb72d3388..08276395a 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1168,32 +1168,34 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") - case .beginForInLoop: + case .beginPlainForInLoop: let OBJ = input(0) - if instr.numInputs == 2 { // Iterator is declared elsewhere - let V = input(1) - w.emit("for (\(V) in \(OBJ)) {") - } else { // Iterator is declared in the function header - let V = w.declare(instr.innerOutput) - let LET = w.declarationKeyword(for: instr.innerOutput) - w.emit("for (\(LET) \(V) in \(OBJ)) {") - } + let V = w.declare(instr.innerOutput) + let LET = w.declarationKeyword(for: instr.innerOutput) + w.emit("for (\(LET) \(V) in \(OBJ)) {") + w.enterNewBlock() + + case .beginForInLoopWithReassignment: + let OBJ = input(0) + let V = input(1) + w.emit("for (\(V) in \(OBJ)) {") w.enterNewBlock() case .endForInLoop: w.leaveCurrentBlock() w.emit("}") - case .beginForOfLoop: + case .beginPlainForOfLoop: let OBJ = input(0) - if instr.numInputs == 2 { - let V = input(1) - w.emit("for (\(V) of \(OBJ)) {") - } else { - let V = w.declare(instr.innerOutput) - let LET = w.declarationKeyword(for: instr.innerOutput) - w.emit("for (\(LET) \(V) of \(OBJ)) {") - } + let V = w.declare(instr.innerOutput) + let LET = w.declarationKeyword(for: instr.innerOutput) + w.emit("for (\(LET) \(V) of \(OBJ)) {") + w.enterNewBlock() + + case .beginForOfLoopWithReassignment: + let OBJ = input(0) + let V = input(1) + w.emit("for (\(V) of \(OBJ)) {") w.enterNewBlock() case .beginForOfLoopWithDestruct(let op): diff --git a/Sources/Fuzzilli/Minimization/BlockReducer.swift b/Sources/Fuzzilli/Minimization/BlockReducer.swift index 9d00f839d..c4cac2ca4 100644 --- a/Sources/Fuzzilli/Minimization/BlockReducer.swift +++ b/Sources/Fuzzilli/Minimization/BlockReducer.swift @@ -51,8 +51,10 @@ struct BlockReducer: Reducer { case .beginWhileLoopHeader, .beginDoWhileLoopBody, .beginForLoopInitializer, - .beginForInLoop, - .beginForOfLoop, + .beginPlainForInLoop, + .beginForInLoopWithReassignment, + .beginPlainForOfLoop, + .beginForOfLoopWithReassignment, .beginForOfLoopWithDestruct, .beginRepeatLoop: reduceLoop(group, with: helper) diff --git a/Sources/Fuzzilli/Minimization/LoopReducer.swift b/Sources/Fuzzilli/Minimization/LoopReducer.swift index 30cf2adde..d48efa1ee 100644 --- a/Sources/Fuzzilli/Minimization/LoopReducer.swift +++ b/Sources/Fuzzilli/Minimization/LoopReducer.swift @@ -40,9 +40,11 @@ struct LoopReducer: Reducer { tryReplaceDoWhileLoopWithRepeatLoop(group, with: helper) case .beginRepeatLoop: tryReduceRepeatLoopIterationCount(group, with: helper) - case .beginForInLoop, - .beginForOfLoop, - .beginForOfLoopWithDestruct: + case .beginPlainForInLoop, + .beginForInLoopWithReassignment, + .beginPlainForOfLoop, + .beginForOfLoopWithReassignment, + .beginForOfLoopWithDestruct: // These loops are (usually) guaranteed to terminate, and should probably anyway not be replaced by repeat-loops. break default: diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 27e86e3f0..914a5e942 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -2269,12 +2269,20 @@ public struct Fuzzilli_Protobuf_EndForLoop: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginForInLoop: Sendable { +public struct Fuzzilli_Protobuf_BeginPlainForInLoop: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var usesPredeclaredIterator: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_BeginForInLoopWithReassignment: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -2291,12 +2299,20 @@ public struct Fuzzilli_Protobuf_EndForInLoop: Sendable { public init() {} } -public struct Fuzzilli_Protobuf_BeginForOfLoop: Sendable { +public struct Fuzzilli_Protobuf_BeginPlainForOfLoop: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - public var usesPredeclaredIterator: Bool = false + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_BeginForOfLoopWithReassignment: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -7108,33 +7124,39 @@ extension Fuzzilli_Protobuf_EndForLoop: SwiftProtobuf.Message, SwiftProtobuf._Me } } -extension Fuzzilli_Protobuf_BeginForInLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginForInLoop" - public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "usesPredeclaredIterator"), - ] +extension Fuzzilli_Protobuf_BeginPlainForInLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginPlainForInLoop" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularBoolField(value: &self.usesPredeclaredIterator) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginPlainForInLoop, rhs: Fuzzilli_Protobuf_BeginPlainForInLoop) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_BeginForInLoopWithReassignment: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginForInLoopWithReassignment" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if self.usesPredeclaredIterator != false { - try visitor.visitSingularBoolField(value: self.usesPredeclaredIterator, fieldNumber: 1) - } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginForInLoop, rhs: Fuzzilli_Protobuf_BeginForInLoop) -> Bool { - if lhs.usesPredeclaredIterator != rhs.usesPredeclaredIterator {return false} + public static func ==(lhs: Fuzzilli_Protobuf_BeginForInLoopWithReassignment, rhs: Fuzzilli_Protobuf_BeginForInLoopWithReassignment) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -7159,33 +7181,39 @@ extension Fuzzilli_Protobuf_EndForInLoop: SwiftProtobuf.Message, SwiftProtobuf._ } } -extension Fuzzilli_Protobuf_BeginForOfLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".BeginForOfLoop" - public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "usesPredeclaredIterator"), - ] +extension Fuzzilli_Protobuf_BeginPlainForOfLoop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginPlainForOfLoop" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularBoolField(value: &self.usesPredeclaredIterator) }() - default: break - } - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginPlainForOfLoop, rhs: Fuzzilli_Protobuf_BeginPlainForOfLoop) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_BeginForOfLoopWithReassignment: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BeginForOfLoopWithReassignment" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { - if self.usesPredeclaredIterator != false { - try visitor.visitSingularBoolField(value: self.usesPredeclaredIterator, fieldNumber: 1) - } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginForOfLoop, rhs: Fuzzilli_Protobuf_BeginForOfLoop) -> Bool { - if lhs.usesPredeclaredIterator != rhs.usesPredeclaredIterator {return false} + public static func ==(lhs: Fuzzilli_Protobuf_BeginForOfLoopWithReassignment, rhs: Fuzzilli_Protobuf_BeginForOfLoopWithReassignment) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 09d1519a4..b22629721 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -680,15 +680,19 @@ message BeginForLoopBody { message EndForLoop { } -message BeginForInLoop { - bool usesPredeclaredIterator = 1; +message BeginPlainForInLoop { +} + +message BeginForInLoopWithReassignment { } message EndForInLoop { } -message BeginForOfLoop { - bool usesPredeclaredIterator = 1; +message BeginPlainForOfLoop { +} + +message BeginForOfLoopWithReassignment { } message BeginForOfLoopWithDestruct { diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index b04230473..0caaf3678 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -1240,12 +1240,20 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endForLoop(newValue)} } - public var beginForInLoop: Fuzzilli_Protobuf_BeginForInLoop { + public var beginPlainForInLoop: Fuzzilli_Protobuf_BeginPlainForInLoop { get { - if case .beginForInLoop(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginForInLoop() + if case .beginPlainForInLoop(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginPlainForInLoop() } - set {operation = .beginForInLoop(newValue)} + set {operation = .beginPlainForInLoop(newValue)} + } + + public var beginForInLoopWithReassignment: Fuzzilli_Protobuf_BeginForInLoopWithReassignment { + get { + if case .beginForInLoopWithReassignment(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginForInLoopWithReassignment() + } + set {operation = .beginForInLoopWithReassignment(newValue)} } public var endForInLoop: Fuzzilli_Protobuf_EndForInLoop { @@ -1256,12 +1264,20 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .endForInLoop(newValue)} } - public var beginForOfLoop: Fuzzilli_Protobuf_BeginForOfLoop { + public var beginPlainForOfLoop: Fuzzilli_Protobuf_BeginPlainForOfLoop { get { - if case .beginForOfLoop(let v)? = operation {return v} - return Fuzzilli_Protobuf_BeginForOfLoop() + if case .beginPlainForOfLoop(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginPlainForOfLoop() } - set {operation = .beginForOfLoop(newValue)} + set {operation = .beginPlainForOfLoop(newValue)} + } + + public var beginForOfLoopWithReassignment: Fuzzilli_Protobuf_BeginForOfLoopWithReassignment { + get { + if case .beginForOfLoopWithReassignment(let v)? = operation {return v} + return Fuzzilli_Protobuf_BeginForOfLoopWithReassignment() + } + set {operation = .beginForOfLoopWithReassignment(newValue)} } public var beginForOfLoopWithDestruct: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct { @@ -1624,9 +1640,11 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case beginForLoopAfterthought(Fuzzilli_Protobuf_BeginForLoopAfterthought) case beginForLoopBody(Fuzzilli_Protobuf_BeginForLoopBody) case endForLoop(Fuzzilli_Protobuf_EndForLoop) - case beginForInLoop(Fuzzilli_Protobuf_BeginForInLoop) + case beginPlainForInLoop(Fuzzilli_Protobuf_BeginPlainForInLoop) + case beginForInLoopWithReassignment(Fuzzilli_Protobuf_BeginForInLoopWithReassignment) case endForInLoop(Fuzzilli_Protobuf_EndForInLoop) - case beginForOfLoop(Fuzzilli_Protobuf_BeginForOfLoop) + case beginPlainForOfLoop(Fuzzilli_Protobuf_BeginPlainForOfLoop) + case beginForOfLoopWithReassignment(Fuzzilli_Protobuf_BeginForOfLoopWithReassignment) case beginForOfLoopWithDestruct(Fuzzilli_Protobuf_BeginForOfLoopWithDestruct) case endForOfLoop(Fuzzilli_Protobuf_EndForOfLoop) case beginRepeatLoop(Fuzzilli_Protobuf_BeginRepeatLoop) @@ -1852,35 +1870,37 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M 148: .same(proto: "beginForLoopAfterthought"), 149: .same(proto: "beginForLoopBody"), 150: .same(proto: "endForLoop"), - 151: .same(proto: "beginForInLoop"), - 152: .same(proto: "endForInLoop"), - 153: .same(proto: "beginForOfLoop"), - 154: .same(proto: "beginForOfLoopWithDestruct"), - 155: .same(proto: "endForOfLoop"), - 156: .same(proto: "beginRepeatLoop"), - 157: .same(proto: "endRepeatLoop"), - 158: .same(proto: "loopBreak"), - 159: .same(proto: "loopContinue"), - 160: .same(proto: "beginTry"), - 161: .same(proto: "beginCatch"), - 162: .same(proto: "beginFinally"), - 163: .same(proto: "endTryCatchFinally"), - 164: .same(proto: "throwException"), - 165: .same(proto: "beginCodeString"), - 166: .same(proto: "endCodeString"), - 167: .same(proto: "beginBlockStatement"), - 168: .same(proto: "endBlockStatement"), - 169: .same(proto: "beginSwitch"), - 170: .same(proto: "beginSwitchCase"), - 171: .same(proto: "beginSwitchDefaultCase"), - 172: .same(proto: "endSwitchCase"), - 173: .same(proto: "endSwitch"), - 174: .same(proto: "switchBreak"), - 175: .same(proto: "loadNewTarget"), - 176: .same(proto: "print"), - 177: .same(proto: "explore"), - 178: .same(proto: "probe"), - 179: .same(proto: "fixup"), + 151: .same(proto: "beginPlainForInLoop"), + 152: .same(proto: "beginForInLoopWithReassignment"), + 153: .same(proto: "endForInLoop"), + 154: .same(proto: "beginPlainForOfLoop"), + 155: .same(proto: "beginForOfLoopWithReassignment"), + 156: .same(proto: "beginForOfLoopWithDestruct"), + 157: .same(proto: "endForOfLoop"), + 158: .same(proto: "beginRepeatLoop"), + 159: .same(proto: "endRepeatLoop"), + 160: .same(proto: "loopBreak"), + 161: .same(proto: "loopContinue"), + 162: .same(proto: "beginTry"), + 163: .same(proto: "beginCatch"), + 164: .same(proto: "beginFinally"), + 165: .same(proto: "endTryCatchFinally"), + 166: .same(proto: "throwException"), + 167: .same(proto: "beginCodeString"), + 168: .same(proto: "endCodeString"), + 169: .same(proto: "beginBlockStatement"), + 170: .same(proto: "endBlockStatement"), + 171: .same(proto: "beginSwitch"), + 172: .same(proto: "beginSwitchCase"), + 173: .same(proto: "beginSwitchDefaultCase"), + 174: .same(proto: "endSwitchCase"), + 175: .same(proto: "endSwitch"), + 176: .same(proto: "switchBreak"), + 177: .same(proto: "loadNewTarget"), + 178: .same(proto: "print"), + 179: .same(proto: "explore"), + 180: .same(proto: "probe"), + 181: .same(proto: "fixup"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -3823,19 +3843,32 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M } }() case 151: try { - var v: Fuzzilli_Protobuf_BeginForInLoop? + var v: Fuzzilli_Protobuf_BeginPlainForInLoop? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginForInLoop(let m) = current {v = m} + if case .beginPlainForInLoop(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginForInLoop(v) + self.operation = .beginPlainForInLoop(v) } }() case 152: try { + var v: Fuzzilli_Protobuf_BeginForInLoopWithReassignment? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginForInLoopWithReassignment(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginForInLoopWithReassignment(v) + } + }() + case 153: try { var v: Fuzzilli_Protobuf_EndForInLoop? var hadOneofValue = false if let current = self.operation { @@ -3848,20 +3881,33 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForInLoop(v) } }() - case 153: try { - var v: Fuzzilli_Protobuf_BeginForOfLoop? + case 154: try { + var v: Fuzzilli_Protobuf_BeginPlainForOfLoop? var hadOneofValue = false if let current = self.operation { hadOneofValue = true - if case .beginForOfLoop(let m) = current {v = m} + if case .beginPlainForOfLoop(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.operation = .beginForOfLoop(v) + self.operation = .beginPlainForOfLoop(v) } }() - case 154: try { + case 155: try { + var v: Fuzzilli_Protobuf_BeginForOfLoopWithReassignment? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .beginForOfLoopWithReassignment(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .beginForOfLoopWithReassignment(v) + } + }() + case 156: try { var v: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct? var hadOneofValue = false if let current = self.operation { @@ -3874,7 +3920,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForOfLoopWithDestruct(v) } }() - case 155: try { + case 157: try { var v: Fuzzilli_Protobuf_EndForOfLoop? var hadOneofValue = false if let current = self.operation { @@ -3887,7 +3933,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForOfLoop(v) } }() - case 156: try { + case 158: try { var v: Fuzzilli_Protobuf_BeginRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -3900,7 +3946,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginRepeatLoop(v) } }() - case 157: try { + case 159: try { var v: Fuzzilli_Protobuf_EndRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -3913,7 +3959,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endRepeatLoop(v) } }() - case 158: try { + case 160: try { var v: Fuzzilli_Protobuf_LoopBreak? var hadOneofValue = false if let current = self.operation { @@ -3926,7 +3972,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopBreak(v) } }() - case 159: try { + case 161: try { var v: Fuzzilli_Protobuf_LoopContinue? var hadOneofValue = false if let current = self.operation { @@ -3939,7 +3985,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopContinue(v) } }() - case 160: try { + case 162: try { var v: Fuzzilli_Protobuf_BeginTry? var hadOneofValue = false if let current = self.operation { @@ -3952,7 +3998,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginTry(v) } }() - case 161: try { + case 163: try { var v: Fuzzilli_Protobuf_BeginCatch? var hadOneofValue = false if let current = self.operation { @@ -3965,7 +4011,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCatch(v) } }() - case 162: try { + case 164: try { var v: Fuzzilli_Protobuf_BeginFinally? var hadOneofValue = false if let current = self.operation { @@ -3978,7 +4024,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginFinally(v) } }() - case 163: try { + case 165: try { var v: Fuzzilli_Protobuf_EndTryCatchFinally? var hadOneofValue = false if let current = self.operation { @@ -3991,7 +4037,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endTryCatchFinally(v) } }() - case 164: try { + case 166: try { var v: Fuzzilli_Protobuf_ThrowException? var hadOneofValue = false if let current = self.operation { @@ -4004,7 +4050,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .throwException(v) } }() - case 165: try { + case 167: try { var v: Fuzzilli_Protobuf_BeginCodeString? var hadOneofValue = false if let current = self.operation { @@ -4017,7 +4063,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCodeString(v) } }() - case 166: try { + case 168: try { var v: Fuzzilli_Protobuf_EndCodeString? var hadOneofValue = false if let current = self.operation { @@ -4030,7 +4076,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endCodeString(v) } }() - case 167: try { + case 169: try { var v: Fuzzilli_Protobuf_BeginBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -4043,7 +4089,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginBlockStatement(v) } }() - case 168: try { + case 170: try { var v: Fuzzilli_Protobuf_EndBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -4056,7 +4102,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endBlockStatement(v) } }() - case 169: try { + case 171: try { var v: Fuzzilli_Protobuf_BeginSwitch? var hadOneofValue = false if let current = self.operation { @@ -4069,7 +4115,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitch(v) } }() - case 170: try { + case 172: try { var v: Fuzzilli_Protobuf_BeginSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -4082,7 +4128,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchCase(v) } }() - case 171: try { + case 173: try { var v: Fuzzilli_Protobuf_BeginSwitchDefaultCase? var hadOneofValue = false if let current = self.operation { @@ -4095,7 +4141,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchDefaultCase(v) } }() - case 172: try { + case 174: try { var v: Fuzzilli_Protobuf_EndSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -4108,7 +4154,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitchCase(v) } }() - case 173: try { + case 175: try { var v: Fuzzilli_Protobuf_EndSwitch? var hadOneofValue = false if let current = self.operation { @@ -4121,7 +4167,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitch(v) } }() - case 174: try { + case 176: try { var v: Fuzzilli_Protobuf_SwitchBreak? var hadOneofValue = false if let current = self.operation { @@ -4134,7 +4180,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .switchBreak(v) } }() - case 175: try { + case 177: try { var v: Fuzzilli_Protobuf_LoadNewTarget? var hadOneofValue = false if let current = self.operation { @@ -4147,7 +4193,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loadNewTarget(v) } }() - case 176: try { + case 178: try { var v: Fuzzilli_Protobuf_Print? var hadOneofValue = false if let current = self.operation { @@ -4160,7 +4206,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .print(v) } }() - case 177: try { + case 179: try { var v: Fuzzilli_Protobuf_Explore? var hadOneofValue = false if let current = self.operation { @@ -4173,7 +4219,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .explore(v) } }() - case 178: try { + case 180: try { var v: Fuzzilli_Protobuf_Probe? var hadOneofValue = false if let current = self.operation { @@ -4186,7 +4232,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .probe(v) } }() - case 179: try { + case 181: try { var v: Fuzzilli_Protobuf_Fixup? var hadOneofValue = false if let current = self.operation { @@ -4809,121 +4855,129 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .endForLoop(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 150) }() - case .beginForInLoop?: try { - guard case .beginForInLoop(let v)? = self.operation else { preconditionFailure() } + case .beginPlainForInLoop?: try { + guard case .beginPlainForInLoop(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 151) }() - case .endForInLoop?: try { - guard case .endForInLoop(let v)? = self.operation else { preconditionFailure() } + case .beginForInLoopWithReassignment?: try { + guard case .beginForInLoopWithReassignment(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 152) }() - case .beginForOfLoop?: try { - guard case .beginForOfLoop(let v)? = self.operation else { preconditionFailure() } + case .endForInLoop?: try { + guard case .endForInLoop(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 153) }() + case .beginPlainForOfLoop?: try { + guard case .beginPlainForOfLoop(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 154) + }() + case .beginForOfLoopWithReassignment?: try { + guard case .beginForOfLoopWithReassignment(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 155) + }() case .beginForOfLoopWithDestruct?: try { guard case .beginForOfLoopWithDestruct(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 154) + try visitor.visitSingularMessageField(value: v, fieldNumber: 156) }() case .endForOfLoop?: try { guard case .endForOfLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 155) + try visitor.visitSingularMessageField(value: v, fieldNumber: 157) }() case .beginRepeatLoop?: try { guard case .beginRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 156) + try visitor.visitSingularMessageField(value: v, fieldNumber: 158) }() case .endRepeatLoop?: try { guard case .endRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 157) + try visitor.visitSingularMessageField(value: v, fieldNumber: 159) }() case .loopBreak?: try { guard case .loopBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 158) + try visitor.visitSingularMessageField(value: v, fieldNumber: 160) }() case .loopContinue?: try { guard case .loopContinue(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 159) + try visitor.visitSingularMessageField(value: v, fieldNumber: 161) }() case .beginTry?: try { guard case .beginTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 160) + try visitor.visitSingularMessageField(value: v, fieldNumber: 162) }() case .beginCatch?: try { guard case .beginCatch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 161) + try visitor.visitSingularMessageField(value: v, fieldNumber: 163) }() case .beginFinally?: try { guard case .beginFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 162) + try visitor.visitSingularMessageField(value: v, fieldNumber: 164) }() case .endTryCatchFinally?: try { guard case .endTryCatchFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 163) + try visitor.visitSingularMessageField(value: v, fieldNumber: 165) }() case .throwException?: try { guard case .throwException(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 164) + try visitor.visitSingularMessageField(value: v, fieldNumber: 166) }() case .beginCodeString?: try { guard case .beginCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 165) + try visitor.visitSingularMessageField(value: v, fieldNumber: 167) }() case .endCodeString?: try { guard case .endCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 166) + try visitor.visitSingularMessageField(value: v, fieldNumber: 168) }() case .beginBlockStatement?: try { guard case .beginBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 167) + try visitor.visitSingularMessageField(value: v, fieldNumber: 169) }() case .endBlockStatement?: try { guard case .endBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 168) + try visitor.visitSingularMessageField(value: v, fieldNumber: 170) }() case .beginSwitch?: try { guard case .beginSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 169) + try visitor.visitSingularMessageField(value: v, fieldNumber: 171) }() case .beginSwitchCase?: try { guard case .beginSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 170) + try visitor.visitSingularMessageField(value: v, fieldNumber: 172) }() case .beginSwitchDefaultCase?: try { guard case .beginSwitchDefaultCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 171) + try visitor.visitSingularMessageField(value: v, fieldNumber: 173) }() case .endSwitchCase?: try { guard case .endSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 172) + try visitor.visitSingularMessageField(value: v, fieldNumber: 174) }() case .endSwitch?: try { guard case .endSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 173) + try visitor.visitSingularMessageField(value: v, fieldNumber: 175) }() case .switchBreak?: try { guard case .switchBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 174) + try visitor.visitSingularMessageField(value: v, fieldNumber: 176) }() case .loadNewTarget?: try { guard case .loadNewTarget(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 175) + try visitor.visitSingularMessageField(value: v, fieldNumber: 177) }() case .print?: try { guard case .print(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 176) + try visitor.visitSingularMessageField(value: v, fieldNumber: 178) }() case .explore?: try { guard case .explore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 177) + try visitor.visitSingularMessageField(value: v, fieldNumber: 179) }() case .probe?: try { guard case .probe(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 178) + try visitor.visitSingularMessageField(value: v, fieldNumber: 180) }() case .fixup?: try { guard case .fixup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 179) + try visitor.visitSingularMessageField(value: v, fieldNumber: 181) }() case nil: break } diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index c8da3a390..5c9223ca1 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -174,35 +174,37 @@ message Instruction { BeginForLoopAfterthought beginForLoopAfterthought = 148; BeginForLoopBody beginForLoopBody = 149; EndForLoop endForLoop = 150; - BeginForInLoop beginForInLoop = 151; - EndForInLoop endForInLoop = 152; - BeginForOfLoop beginForOfLoop = 153; - BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 154; - EndForOfLoop endForOfLoop = 155; - BeginRepeatLoop beginRepeatLoop = 156; - EndRepeatLoop endRepeatLoop = 157; - LoopBreak loopBreak = 158; - LoopContinue loopContinue = 159; - BeginTry beginTry = 160; - BeginCatch beginCatch = 161; - BeginFinally beginFinally = 162; - EndTryCatchFinally endTryCatchFinally = 163; - ThrowException throwException = 164; - BeginCodeString beginCodeString = 165; - EndCodeString endCodeString = 166; - BeginBlockStatement beginBlockStatement = 167; - EndBlockStatement endBlockStatement = 168; - BeginSwitch beginSwitch = 169; - BeginSwitchCase beginSwitchCase = 170; - BeginSwitchDefaultCase beginSwitchDefaultCase = 171; - EndSwitchCase endSwitchCase = 172; - EndSwitch endSwitch = 173; - SwitchBreak switchBreak = 174; - LoadNewTarget loadNewTarget = 175; - Print print = 176; - Explore explore = 177; - Probe probe = 178; - Fixup fixup = 179; + BeginPlainForInLoop beginPlainForInLoop = 151; + BeginForInLoopWithReassignment beginForInLoopWithReassignment = 152; + EndForInLoop endForInLoop = 153; + BeginPlainForOfLoop beginPlainForOfLoop = 154; + BeginForOfLoopWithReassignment beginForOfLoopWithReassignment = 155; + BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 156; + EndForOfLoop endForOfLoop = 157; + BeginRepeatLoop beginRepeatLoop = 158; + EndRepeatLoop endRepeatLoop = 159; + LoopBreak loopBreak = 160; + LoopContinue loopContinue = 161; + BeginTry beginTry = 162; + BeginCatch beginCatch = 163; + BeginFinally beginFinally = 164; + EndTryCatchFinally endTryCatchFinally = 165; + ThrowException throwException = 166; + BeginCodeString beginCodeString = 167; + EndCodeString endCodeString = 168; + BeginBlockStatement beginBlockStatement = 169; + EndBlockStatement endBlockStatement = 170; + BeginSwitch beginSwitch = 171; + BeginSwitchCase beginSwitchCase = 172; + BeginSwitchDefaultCase beginSwitchDefaultCase = 173; + EndSwitchCase endSwitchCase = 174; + EndSwitch endSwitch = 175; + SwitchBreak switchBreak = 176; + LoadNewTarget loadNewTarget = 177; + Print print = 178; + Explore explore = 179; + Probe probe = 180; + Fixup fixup = 181; } } diff --git a/Tests/FuzzilliTests/AnalyzerTest.swift b/Tests/FuzzilliTests/AnalyzerTest.swift index 1dac85577..3ec469db2 100644 --- a/Tests/FuzzilliTests/AnalyzerTest.swift +++ b/Tests/FuzzilliTests/AnalyzerTest.swift @@ -257,15 +257,24 @@ class AnalyzerTests: XCTestCase { XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } - b.buildForInLoop(args[1]) { _ in + b.buildPlainForInLoop(args[1]) { _ in XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } - b.buildForOfLoop(args[2]) { _ in + let existingVar = b.loadInt(42) + b.buildForInLoopWithReassignment(args[1], existingVar) { XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } - b.buildForOfLoop(args[3], selecting: [0, 1, 3]) { _ in + b.buildPlainForOfLoop(args[2]) { _ in + XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) + } + + b.buildForOfLoopWithReassignment(args[2], existingVar) { + XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) + } + + b.buildForOfLoopWithDestruct(args[3], selecting: [0, 1, 3]) { _ in XCTAssertEqual(b.context, [.javascript, .subroutine, .loop]) } diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index 5ffd550ec..353605580 100644 --- a/Tests/FuzzilliTests/JSTyperTests.swift +++ b/Tests/FuzzilliTests/JSTyperTests.swift @@ -681,12 +681,12 @@ class JSTyperTests: XCTestCase { } break case 2: - b.buildForInLoop(obj) { loopVar in + b.buildPlainForInLoop(obj) { loopVar in XCTAssertEqual(b.type(of: loopVar), .string) body() } case 3: - b.buildForOfLoop(obj) { loopVar in + b.buildPlainForOfLoop(obj) { loopVar in XCTAssertEqual(b.type(of: loopVar), .anything) body() } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 8371f9f16..cb3830b27 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -2579,9 +2579,9 @@ class LifterTests: XCTestCase { let a3 = b.createArray(with: [b.loadInt(30), b.loadInt(31), b.loadInt(32)]) let a4 = b.createArray(with: [a1, a2, a3]) let print = b.loadBuiltin("print") - b.buildForOfLoop(a4, selecting: [0,2], hasRestElement: true) { args in + b.buildForOfLoopWithDestruct(a4, selecting: [0,2], hasRestElement: true) { args in b.callFunction(print, withArgs: [args[0]]) - b.buildForOfLoop(args[1]) { v in + b.buildPlainForOfLoop(args[1]) { v in b.callFunction(print, withArgs: [v]) } } @@ -2602,13 +2602,40 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } + func testForLoopWithReassignment() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.createObject(with: ["x": b.loadInt(42)]) + let existing = b.loadString("initial") + b.buildForInLoopWithReassignment(obj, existing) { + b.reassign(existing, to: b.loadString("updated")) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const o1 = { + "x": 42, + }; + let v2 = "initial"; + for (v2 in o1) { + v2 = "updated"; + } + + """ + + XCTAssertEqual(actual, expected) + } + func testBlockStatements() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() let v0 = b.loadInt(1337) let v1 = b.createObject(with: ["a": v0]) - b.buildForInLoop(v1) { v2 in + b.buildPlainForInLoop(v1) { v2 in b.blockStatement { let v3 = b.loadInt(1337) b.reassign(v2, to: v3) diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 918af4279..326ce000b 100644 --- a/Tests/FuzzilliTests/ProgramBuilderTest.swift +++ b/Tests/FuzzilliTests/ProgramBuilderTest.swift @@ -2213,7 +2213,7 @@ class ProgramBuilderTests: XCTestCase { var o1 = b.createObject(with: ["foo": i, "bar": s, "baz": f]) b.loadString("unused") var o2 = b.createObject(with: [:]) - b.buildForInLoop(o1) { p in + b.buildPlainForInLoop(o1) { p in let i = b.loadInt(1337) b.loadString("unusedButPartOfBody") splicePoint = b.indexOfNextInstruction() @@ -2236,7 +2236,7 @@ class ProgramBuilderTests: XCTestCase { f = b.loadFloat(13.37) o1 = b.createObject(with: ["foo": i, "bar": s, "baz": f]) o2 = b.createObject(with: [:]) - b.buildForInLoop(o1) { p in + b.buildPlainForInLoop(o1) { p in let i = b.loadInt(1337) b.loadString("unusedButPartOfBody") b.setComputedProperty(p, of: o2, to: i) From 89d2d77a9e3cb6660863c8f053f458e9f52f6da2 Mon Sep 17 00:00:00 2001 From: Tobias Wienand Date: Sat, 7 Dec 2024 13:59:36 +0100 Subject: [PATCH 4/6] Implements global property iterator for loop --- Sources/Fuzzilli/Compiler/Compiler.swift | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Compiler.swift b/Sources/Fuzzilli/Compiler/Compiler.swift index fcb6f4a1a..511c3deb9 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -431,9 +431,12 @@ public class JavaScriptCompiler { emit(EndForInLoop()) case .identifier(let identifier): - guard let loopVar = lookupIdentifier(identifier.name) else { - // TODO instead of throwing an error, we should create a global property with the identifier name - throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-in loop.") + let loopVar: Variable + if let existingVar = lookupIdentifier(identifier.name) { + loopVar = existingVar + } else { + loopVar = emit(LoadNamedVariable(identifier.name)).output + map(identifier.name, to: loopVar) } emit(BeginForInLoopWithReassignment(), withInputs: [obj, loopVar]) try enterNewScope { @@ -459,9 +462,12 @@ public class JavaScriptCompiler { emit(EndForOfLoop()) case .identifier(let identifier): - guard let loopVar = lookupIdentifier(identifier.name) else { - // TODO instead of throwing an error, we should create a global property with the identifier name - throw CompilerError.unsupportedFeatureError("Identifier '\(identifier.name)' not found for for-of loop.") + let loopVar: Variable + if let existingVar = lookupIdentifier(identifier.name) { + loopVar = existingVar + } else { + loopVar = emit(LoadNamedVariable(identifier.name)).output + map(identifier.name, to: loopVar) } emit(BeginForOfLoopWithReassignment(), withInputs: [obj, loopVar]) try enterNewScope { From c75890c59dd63f6ec4598367cf8c95ac65a84989 Mon Sep 17 00:00:00 2001 From: Tobias Wienand Date: Sat, 7 Dec 2024 14:29:35 +0100 Subject: [PATCH 5/6] Adds a TODO --- Sources/Fuzzilli/FuzzIL/JsOperations.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index e4b3b1d57..009249736 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1985,7 +1985,7 @@ final class EndForInLoop: JsOperation { super.init(attributes: .isBlockEnd) } } - +// TODO: Support even more types of for loops, e.g.: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#examples final class BeginPlainForOfLoop: JsOperation { override var opcode: Opcode { .beginPlainForOfLoop(self) } init() { From 39f77f13dcdfd3daaee334c71f07c5cadf08be99 Mon Sep 17 00:00:00 2001 From: Tobias Wienand Date: Tue, 17 Dec 2024 06:31:22 +0100 Subject: [PATCH 6/6] Implements compilation of forof/forin loop with global property as iterator variable --- Sources/Fuzzilli/Compiler/Parser/parser.js | 12 ++++++++++-- Sources/Fuzzilli/Lifting/JavaScriptLifter.swift | 6 +++--- Tests/FuzzilliTests/CompilerTests/advanced_loops.js | 11 +++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index f45fbb43d..fd7f9b76e 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -274,7 +274,11 @@ function parse(script, proto) { let initDecl = { name: decl.id.name }; assert(decl.init == null, "Expected no initial value for the variable declared as part of a for-in loop") forInLoop.variableDeclarator = make('VariableDeclarator', initDecl); - } else forInLoop.identifier = make('Identifier', { name: node.left.name }); + } else if (node.left.type === 'Identifier') { + forOfLoop.identifier = make('Identifier', { name: node.left.name }); + } else { + throw "Unsupported left side of for-in loop: " + node.left.type; + } forInLoop.right = visitExpression(node.right); forInLoop.body = visitStatement(node.body); return makeStatement('ForInLoop', forInLoop); @@ -287,7 +291,11 @@ function parse(script, proto) { let initDecl = { name: decl.id.name }; assert(decl.init == null, "Expected no initial value for the variable declared as part of a for-of loop") forOfLoop.variableDeclarator = make('VariableDeclarator', initDecl); - } else forOfLoop.identifier = make('Identifier', { name: node.left.name }); + } else if (node.left.type === 'Identifier') { + forOfLoop.identifier = make('Identifier', { name: node.left.name }); + } else { + throw "Unsupported left side of for-of loop: " + node.left.type; + } forOfLoop.right = visitExpression(node.right); forOfLoop.body = visitStatement(node.body); return makeStatement('ForOfLoop', forOfLoop); diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index 08276395a..91b244271 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -882,7 +882,7 @@ public class JavaScriptLifter: Lifter { w.assign(expr, to: instr.output) case .loadNamedVariable(let op): - w.assign(Identifier.new(op.variableName), to: instr.output) + w.assign(Identifier.new(op.variableName), to: instr.output, forceInlining: true) case .storeNamedVariable(let op): let NAME = op.variableName @@ -1548,13 +1548,13 @@ public class JavaScriptLifter: Lifter { /// /// If the expression can be inlined, it will be associated with the variable and returned at its use. If the expression cannot be inlined, /// the expression will be emitted either as part of a variable definition or as an expression statement (if the value isn't subsequently used). - mutating func assign(_ expr: Expression, to v: Variable, allowInlining: Bool = true) { + mutating func assign(_ expr: Expression, to v: Variable, allowInlining: Bool = true, forceInlining: Bool = false) { if let V = expressions[v] { // In some situations, for example in the case of guarded operations that require a try-catch around them, // the output variable is declared up-front and so we lift to a variable assignment. assert(V.type === Identifier) emit("\(V) = \(expr);") - } else if allowInlining && shouldTryInlining(expr, producing: v) { + } else if allowInlining && shouldTryInlining(expr, producing: v) || forceInlining { expressions[v] = expr // If this is an effectful expression, it must be the next expression to be evaluated. To ensure that, we // keep a list of all "pending" effectful expressions, which must be executed in FIFO order. diff --git a/Tests/FuzzilliTests/CompilerTests/advanced_loops.js b/Tests/FuzzilliTests/CompilerTests/advanced_loops.js index 7f40a8bff..4e310fec4 100644 --- a/Tests/FuzzilliTests/CompilerTests/advanced_loops.js +++ b/Tests/FuzzilliTests/CompilerTests/advanced_loops.js @@ -89,3 +89,14 @@ for (output("inside for loop initializer"); output("inside for loop condition"), if (!countdown()) break; } resetCounter(); + +for (a of ["new a"]) {} +output("value of a: " + a); + +b = "old b"; +for (b of ["new b"]) {} +output("value of b: " + b); + +var c = "old c"; +for (c of ["new c"]) {} +output("value of c: " + c); \ No newline at end of file