diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 3e712ece..a8167c5e 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2501,19 +2501,41 @@ public class ProgramBuilder { emit(EndForLoop()) } - public func buildForInLoop(_ obj: Variable, _ body: (Variable) -> ()) { - let i = emit(BeginForInLoop(), withInputs: [obj]).innerOutput + public func buildPlainForInLoop(_ obj: Variable, _ name: String, declarationMode: NamedVariableDeclarationMode, _ body: (Variable) -> ()) { + let i: Variable + if declarationMode == .let || declarationMode == .const { + i = emit(BeginPlainForInLoop(name, declarationMode: declarationMode), withInputs: [obj]).innerOutput + } else { + i = emit(BeginPlainForInLoop(name, declarationMode: declarationMode), withInputs: [obj]).output + } 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, _ name: String, declarationMode: NamedVariableDeclarationMode, _ body: (Variable) -> ()) { + let i: Variable + if declarationMode == .let || declarationMode == .const { + i = emit(BeginPlainForOfLoop(name, declarationMode: declarationMode), withInputs: [obj]).innerOutput + } else { + i = emit(BeginPlainForOfLoop(name, declarationMode: declarationMode), withInputs: [obj]).output + } 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 b7323847..729d37a6 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -159,8 +159,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 f520d9b3..d2d0e267 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1420,14 +1420,36 @@ public let CodeGenerators: [CodeGenerator] = [ } }, - RecursiveCodeGenerator("ForInLoopGenerator", inputs: .preferred(.object())) { b, obj in - b.buildForInLoop(obj) { _ in + RecursiveCodeGenerator("PlainForInLoopGenerator", inputs: .preferred(.object())) { b, obj in + // .none declaration mode is for reassigning loops + let validDeclarationModes = NamedVariableDeclarationMode.allCases.filter { $0 != .none } + let name = b.randomCustomPropertyName() + let declarationMode = chooseUniform(from: NamedVariableDeclarationMode.allCases) + b.buildPlainForInLoop(obj, name, declarationMode: declarationMode) { _ in + b.buildRecursive() + } + }, + + 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 + let validDeclarationModes = NamedVariableDeclarationMode.allCases.filter { $0 != .none } + let name = b.randomCustomPropertyName() + let declarationMode = chooseUniform(from: NamedVariableDeclarationMode.allCases) + b.buildPlainForOfLoop(obj, name, declarationMode: declarationMode) { _ in b.buildRecursive() } }, - RecursiveCodeGenerator("ForOfLoopGenerator", inputs: .preferred(.iterable)) { b, obj in - b.buildForOfLoop(obj) { _ in + RecursiveCodeGenerator("ForOfLoopWithReassignmentGenerator", inputs: .preferred(.iterable)) { b, obj in + let existing = b.randomVariable() + b.buildForOfLoopWithReassignment(obj, existing) { b.buildRecursive() } }, @@ -1444,7 +1466,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 ead5d884..1da7a321 100644 --- a/Sources/Fuzzilli/Compiler/Compiler.swift +++ b/Sources/Fuzzilli/Compiler/Compiler.swift @@ -417,36 +417,117 @@ public class JavaScriptCompiler { emit(EndForLoop()) 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 .variableDeclaration(let variableDeclaration): + guard variableDeclaration.declarations.count == 1 else { + throw CompilerError.invalidNodeError("Expected only one variable to be declared in a for-in loop") + } + let decl = variableDeclaration.declarations[0] + guard !decl.hasValue else { + throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-in loop") + } + let kind: NamedVariableDeclarationMode + switch variableDeclaration.kind { + case .var: + kind = .var + case .let: + kind = .let + case .const: + kind = .const + case .UNRECOGNIZED(let type): + throw CompilerError.invalidNodeError("invalid variable declaration type \(type)") + } + let newVariableName = decl.name + let loopVar : Variable + if kind == .const || kind == .let { + loopVar = emit(BeginPlainForInLoop(newVariableName, declarationMode: kind), withInputs: [obj]).innerOutput + try enterNewScope { + map(newVariableName, to: loopVar) + try compileBody(forInLoop.body) + } + } else { + loopVar = emit(BeginPlainForInLoop(newVariableName, declarationMode: kind), withInputs: [obj]).output + map(newVariableName, to: loopVar) + try enterNewScope { + 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): + if let pre_existing_variable = lookupIdentifier(identifier.name) { + emit(BeginForInLoopWithReassignment(), withInputs: [obj, pre_existing_variable]) + } else { + // A for-in loop with an identifier that is not previously declared is implicitly a global variable. + let new_global_iterator = emit(BeginPlainForInLoop(identifier.name, declarationMode: .global), withInputs: [obj]).output + map(identifier.name, to: new_global_iterator) + } + 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 .variableDeclaration(let variableDeclaration): + guard variableDeclaration.declarations.count == 1 else { + throw CompilerError.invalidNodeError("Expected only one variable to be declared in a for-of loop") + } + let decl = variableDeclaration.declarations[0] + guard !decl.hasValue else { + throw CompilerError.invalidNodeError("Expected no initial value for the variable declared in a for-of loop") + } + let kind: NamedVariableDeclarationMode + switch variableDeclaration.kind { + case .var: + kind = .var + case .let: + kind = .let + case .const: + kind = .const + case .UNRECOGNIZED(let type): + throw CompilerError.invalidNodeError("invalid variable declaration type \(type)") + } + let newVariableName = decl.name + let loopVar : Variable + if kind == .const || kind == .let { + loopVar = emit(BeginPlainForOfLoop(newVariableName, declarationMode: kind), withInputs: [obj]).innerOutput + try enterNewScope { + map(newVariableName, to: loopVar) + try compileBody(forOfLoop.body) + } + } else { + loopVar = emit(BeginPlainForOfLoop(newVariableName, declarationMode: kind), withInputs: [obj]).output + map(newVariableName, to: loopVar) + try enterNewScope { + try compileBody(forOfLoop.body) + } + } + emit(EndForOfLoop()) - emit(EndForOfLoop()) + case .identifier(let identifier): + if let pre_existing_variable = lookupIdentifier(identifier.name) { + emit(BeginForOfLoopWithReassignment(), withInputs: [obj, pre_existing_variable]) + } else { + // A for-of loop with an identifier that is not previously declared is implicitly a global variable. + let new_global_iterator = emit(BeginPlainForOfLoop(identifier.name, declarationMode: .global), withInputs: [obj]).output + map(identifier.name, to: new_global_iterator) + } + 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 @@ -597,7 +678,6 @@ public class JavaScriptCompiler { let v = emit(CreateNamedVariable(identifier.name, declarationMode: .none)).output // Cache the variable in case it is reused again to avoid emitting multiple // CreateNamedVariable operations for the same variable. - map(identifier.name, to: v) return v case .numberLiteral(let literal): @@ -722,13 +802,15 @@ public class JavaScriptCompiler { case .identifier(let identifier): // Try to lookup the variable belonging to the identifier. If there is none, we're (probably) dealing with // an access to a global variable/builtin or a hoisted variable access. In the case, create a named variable. - let lhs = lookupIdentifier(identifier.name) ?? emit(CreateNamedVariable(identifier.name, declarationMode: .none)).output + guard let lhs = lookupIdentifier(identifier.name) else { + let lhs = emit(CreateNamedVariable(identifier.name, declarationMode: .global), withInputs: [rhs]).output + map(identifier.name, to: lhs) + break + } // Compile to a Reassign or Update operation switch assignmentExpression.operator { case "=": - // TODO(saelo): if we're assigning to a named variable, we could also generate a declaration - // of a global variable here instead. Probably it doeesn't matter in practice though. emit(Reassign(), withInputs: [lhs, rhs]) default: // It's something like "+=", "-=", etc. diff --git a/Sources/Fuzzilli/Compiler/Parser/parser.js b/Sources/Fuzzilli/Compiler/Parser/parser.js index 09e88eeb..7b12d6d9 100644 --- a/Sources/Fuzzilli/Compiler/Parser/parser.js +++ b/Sources/Fuzzilli/Compiler/Parser/parser.js @@ -11,6 +11,12 @@ let astProtobufDefinitionPath = process.argv[2]; let inputFilePath = process.argv[3]; let outputFilePath = process.argv[4]; +const varKindMap = { + "var": 0, + "let": 1, + "const": 2 +}; + function assert(cond, msg) { if (!cond) { if (typeof msg !== 'undefined') { @@ -97,15 +103,9 @@ function parse(script, proto) { } function visitVariableDeclaration(node) { - let kind; - if (node.kind === "var") { - kind = 0; - } else if (node.kind === "let") { - kind = 1; - } else if (node.kind === "const") { - kind = 2; - } else { - throw "Unknown variable declaration kind: " + node.kind; + let kind = varKindMap[node.kind]; + if (kind === undefined) { + throw new Error("Unknown variable declaration kind: " + node.kind); } let declarations = []; @@ -282,25 +282,53 @@ 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") + // TODO: Support destructuring / member expressions + assert(decl.id.type == "Identifier", "Expected identifier for the variable declared as part of a for-in loop") + let kind = varKindMap[node.left.kind]; + if (kind === undefined) { + throw new Error("Unknown variable declaration kind: " + node.kind); + } + forInLoop.variableDeclaration = make('VariableDeclaration', { + kind: kind, + declarations: [initDecl] + }); + } else if (node.left.type === 'Identifier') { + forInLoop.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); } 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") + // TODO: Support destructuring / member expressions + assert(decl.id.type == "Identifier", "Expected identifier for the variable declared as part of a for-of loop") + let kind = varKindMap[node.left.kind]; + if (kind === undefined) { + throw new Error("Unknown variable declaration kind: " + node.kind); + } + forOfLoop.variableDeclaration = make('VariableDeclaration', { + kind: kind, + declarations: [initDecl] + }); + } 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/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 55993724..24e6bfb0 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -801,12 +801,22 @@ extension Instruction: ProtobufConvertible { $0.beginForLoopBody = Fuzzilli_Protobuf_BeginForLoopBody() case .endForLoop: $0.endForLoop = Fuzzilli_Protobuf_EndForLoop() - case .beginForInLoop: - $0.beginForInLoop = Fuzzilli_Protobuf_BeginForInLoop() + case .beginPlainForInLoop(let op): + $0.beginPlainForInLoop = Fuzzilli_Protobuf_BeginPlainForInLoop.with { + $0.variableName = op.variableName + $0.declarationMode = convertEnum(op.declarationMode, NamedVariableDeclarationMode.allCases) + } + case .beginForInLoopWithReassignment: + $0.beginForInLoopWithReassignment = Fuzzilli_Protobuf_BeginForInLoopWithReassignment() case .endForInLoop: $0.endForInLoop = Fuzzilli_Protobuf_EndForInLoop() - case .beginForOfLoop: - $0.beginForOfLoop = Fuzzilli_Protobuf_BeginForOfLoop() + case .beginPlainForOfLoop(let op): + $0.beginPlainForOfLoop = Fuzzilli_Protobuf_BeginPlainForOfLoop.with { + $0.variableName = op.variableName + $0.declarationMode = convertEnum(op.declarationMode, NamedVariableDeclarationMode.allCases) + } + case .beginForOfLoopWithReassignment: + $0.beginForOfLoopWithReassignment = Fuzzilli_Protobuf_BeginForOfLoopWithReassignment() case .beginForOfLoopWithDestruct(let op): $0.beginForOfLoopWithDestruct = Fuzzilli_Protobuf_BeginForOfLoopWithDestruct.with { $0.indices = op.indices.map({ Int32($0) }) @@ -1229,14 +1239,21 @@ extension Instruction: ProtobufConvertible { op = BeginForLoopBody(numLoopVariables: inouts.count) case .endForLoop: op = EndForLoop() - case .beginForInLoop: - op = BeginForInLoop() + case .beginPlainForInLoop(let p): + op = BeginPlainForInLoop(p.variableName, declarationMode: try convertEnum(p.declarationMode, NamedVariableDeclarationMode.allCases)) + case .beginForInLoopWithReassignment: + op = BeginForInLoopWithReassignment() case .endForInLoop: op = EndForInLoop() - case .beginForOfLoop: - op = BeginForOfLoop() + case .beginPlainForOfLoop(let p): + op = BeginPlainForOfLoop(p.variableName, declarationMode: try convertEnum(p.declarationMode, NamedVariableDeclarationMode.allCases)) + 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 dbe210cc..a3ad3640 100644 --- a/Sources/Fuzzilli/FuzzIL/JSTyper.swift +++ b/Sources/Fuzzilli/FuzzIL/JSTyper.swift @@ -220,6 +220,21 @@ public struct JSTyper: Analyzer { let cls = activeClassDefinitions.pop() // Can now compute the full type of the class variable set(cls.output, cls.classType + .constructor(cls.constructorParameters => cls.instanceType)) + case .beginPlainForInLoop(let op): + let declaresInner = op.declarationMode == .let || op.declarationMode == .const + if declaresInner { + set(instr.innerOutput, .string) + } else { + set(instr.output, .string) + } + case .beginPlainForOfLoop(let op): + let declaresInner = op.declarationMode == .let || op.declarationMode == .const + if declaresInner { + set(instr.innerOutput, .anything) + } else { + set(instr.output, .anything) + } + default: // Only instructions starting a block with output variables should be handled here. assert(instr.numOutputs == 0 || !instr.isBlockStart) @@ -283,8 +298,10 @@ public struct JSTyper: Analyzer { case .endForLoop: state.endGroupOfConditionallyExecutingBlocks(typeChanges: &typeChanges) case .beginWhileLoopBody, - .beginForInLoop, - .beginForOfLoop, + .beginPlainForInLoop, + .beginForInLoopWithReassignment, + .beginPlainForOfLoop, + .beginForOfLoopWithReassignment, .beginForOfLoopWithDestruct, .beginRepeatLoop, .beginCodeString: @@ -805,11 +822,27 @@ public struct JSTyper: Analyzer { assert(inputTypes.count == instr.numInnerOutputs) zip(instr.innerOutputs, inputTypes).forEach({ set($0, $1) }) - case .beginForInLoop: - set(instr.innerOutput, .string) + case .beginPlainForInLoop(let op): + let declaresInner = op.declarationMode == .let || op.declarationMode == .const + if declaresInner { + set(instr.innerOutput, .string) + } else { + set(instr.output, .string) + } + + case .beginForInLoopWithReassignment: + set(instr.input(1), .string) - case .beginForOfLoop: - set(instr.innerOutput, .anything) + case .beginPlainForOfLoop(let op): + let declaresInner = op.declarationMode == .let || op.declarationMode == .const + if declaresInner { + set(instr.innerOutput, .anything) + } else { + set(instr.output, .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 832531b4..3d74f310 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -2140,11 +2140,24 @@ final class EndForLoop: JsOperation { } } -final class BeginForInLoop: JsOperation { - override var opcode: Opcode { .beginForInLoop(self) } +final class BeginPlainForInLoop: JsOperation { + override var opcode: Opcode { .beginPlainForInLoop(self) } + let variableName: String + let declarationMode: NamedVariableDeclarationMode + + init(_ variableName: String, declarationMode: NamedVariableDeclarationMode) { + self.variableName = variableName + self.declarationMode = declarationMode + let declaresInner = declarationMode == .let || declarationMode == .const + + super.init(numInputs: 1, numOutputs: declaresInner ? 0 : 1, numInnerOutputs: declaresInner ? 1 : 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + } +} +final class BeginForInLoopWithReassignment: JsOperation { + override var opcode: Opcode { .beginForInLoopWithReassignment(self) } init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + super.init(numInputs: 2, numInnerOutputs: 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) } } @@ -2155,12 +2168,25 @@ 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) } + let variableName: String + let declarationMode: NamedVariableDeclarationMode + + init(_ variableName: String, declarationMode: NamedVariableDeclarationMode) { + self.variableName = variableName + self.declarationMode = declarationMode + let declaresInner = declarationMode == .let || declarationMode == .const -final class BeginForOfLoop: JsOperation { - override var opcode: Opcode { .beginForOfLoop(self) } + super.init(numInputs: 1, numOutputs: declaresInner ? 0 : 1, numInnerOutputs: declaresInner ? 1 : 0, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + } +} +final class BeginForOfLoopWithReassignment: JsOperation { + override var opcode: Opcode { .beginForOfLoopWithReassignment(self) } init() { - super.init(numInputs: 1, numInnerOutputs: 1, attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .loop]) + 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 6e8c31e9..0e0c11a0 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -177,9 +177,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 c687289f..12f474f8 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 .beginForInLoopWithReassignment: + return inputIdx == 1 + case .beginForOfLoopWithReassignment: + return inputIdx == 1 default: return false } @@ -204,9 +208,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 97f9abf7..2cb0cf51 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -673,16 +673,34 @@ public class FuzzILLifter: Lifter { w.decreaseIndentionLevel() w.emit("EndForLoop") - case .beginForInLoop: - w.emit("BeginForInLoop \(input(0)) -> \(innerOutput())") + case .beginPlainForInLoop(let op): + let declaresInner = op.declarationMode == .const || op.declarationMode == .let + if declaresInner { + w.emit("BeginPlainForInLoop \(input(0)) -> '\(op.variableName)', '\(op.declarationMode)', \(innerOutput())") + } else { + w.emit("BeginPlainForInLoop \(input(0)) -> '\(op.variableName)', '\(op.declarationMode)', \(output())") + } + w.increaseIndentionLevel() + + case .beginForInLoopWithReassignment: + w.emit("BeginForInLoopWithReassignment \(input(0)) -> \(input(1))") w.increaseIndentionLevel() case .endForInLoop: w.decreaseIndentionLevel() w.emit("EndForInLoop") - case .beginForOfLoop: - w.emit("BeginForOfLoop \(input(0)) -> \(innerOutput())") + case .beginPlainForOfLoop(let op): + let declaresInner = op.declarationMode == .const || op.declarationMode == .let + if declaresInner { + w.emit("BeginPlainForOfLoop \(input(0)) -> '\(op.variableName)', '\(op.declarationMode)', \(innerOutput())") + } else { + w.emit("BeginPlainForOfLoop \(input(0)) -> '\(op.variableName)', '\(op.declarationMode)', \(output())") + } + 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 eaa89c97..2af47c48 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -1226,22 +1226,38 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("}") - case .beginForInLoop: - let LET = w.declarationKeyword(for: instr.innerOutput) - let V = w.declare(instr.innerOutput) + case .beginPlainForInLoop(let op): + let declaresInner = op.declarationMode == .let || op.declarationMode == .const let OBJ = input(0) - w.emit("for (\(LET) \(V) in \(OBJ)) {") + let LET = op.declarationMode != .global ? "\(op.declarationMode) " : "" + let V = op.variableName + w.declare(declaresInner ? instr.innerOutput : instr.output, as: V) + 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: - let V = w.declare(instr.innerOutput) - let LET = w.declarationKeyword(for: instr.innerOutput) + case .beginPlainForOfLoop(let op): + let declaresInner = op.declarationMode == .let || op.declarationMode == .const + let OBJ = input(0) + let LET = op.declarationMode != .global ? "\(op.declarationMode) " : "" + let V = op.variableName + w.declare(declaresInner ? instr.innerOutput : instr.output, as: V) + w.emit("for (\(LET)\(V) of \(OBJ)) {") + w.enterNewBlock() + + case .beginForOfLoopWithReassignment: let OBJ = input(0) - w.emit("for (\(LET) \(V) of \(OBJ)) {") + 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 9d00f839..c4cac2ca 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/LoopSimplifier.swift b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift index 11169adb..aa15002b 100644 --- a/Sources/Fuzzilli/Minimization/LoopSimplifier.swift +++ b/Sources/Fuzzilli/Minimization/LoopSimplifier.swift @@ -40,9 +40,11 @@ struct LoopSimplifier: 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/ast.pb.swift b/Sources/Fuzzilli/Protobuf/ast.pb.swift index 2f6330e2..aa28398a 100644 --- a/Sources/Fuzzilli/Protobuf/ast.pb.swift +++ b/Sources/Fuzzilli/Protobuf/ast.pb.swift @@ -1,6 +1,5 @@ // DO NOT EDIT. // swift-format-ignore-file -// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: ast.proto @@ -22,6 +21,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -161,31 +161,28 @@ public struct Compiler_Protobuf_BlockStatement: Sendable { public init() {} } -public struct Compiler_Protobuf_VariableDeclarator: @unchecked Sendable { +public struct Compiler_Protobuf_VariableDeclarator: 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 name: String { - get {return _storage._name} - set {_uniqueStorage()._name = newValue} - } + public var name: String = String() /// The value is optional public var value: Compiler_Protobuf_Expression { - get {return _storage._value ?? Compiler_Protobuf_Expression()} - set {_uniqueStorage()._value = newValue} + get {return _value ?? Compiler_Protobuf_Expression()} + set {_value = newValue} } /// Returns true if `value` has been explicitly set. - public var hasValue: Bool {return _storage._value != nil} + public var hasValue: Bool {return self._value != nil} /// Clears the value of `value`. Subsequent reads from it will return its default value. - public mutating func clearValue() {_uniqueStorage()._value = nil} + public mutating func clearValue() {self._value = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _storage = _StorageClass.defaultInstance + fileprivate var _value: Compiler_Protobuf_Expression? = nil } public struct Compiler_Protobuf_VariableDeclaration: Sendable { @@ -702,14 +699,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 variableDeclaration: Compiler_Protobuf_VariableDeclaration { + get { + if case .variableDeclaration(let v)? = _storage._left {return v} + return Compiler_Protobuf_VariableDeclaration() + } + set {_uniqueStorage()._left = .variableDeclaration(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()} @@ -731,6 +740,12 @@ public struct Compiler_Protobuf_ForInLoop: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() + public enum OneOf_Left: Equatable, Sendable { + case variableDeclaration(Compiler_Protobuf_VariableDeclaration) + case identifier(Compiler_Protobuf_Identifier) + + } + public init() {} fileprivate var _storage = _StorageClass.defaultInstance @@ -741,14 +756,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 variableDeclaration: Compiler_Protobuf_VariableDeclaration { + get { + if case .variableDeclaration(let v)? = _storage._left {return v} + return Compiler_Protobuf_VariableDeclaration() + } + set {_uniqueStorage()._left = .variableDeclaration(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()} @@ -770,6 +797,12 @@ public struct Compiler_Protobuf_ForOfLoop: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() + public enum OneOf_Left: Equatable, Sendable { + case variableDeclaration(Compiler_Protobuf_VariableDeclaration) + case identifier(Compiler_Protobuf_Identifier) + + } + public init() {} fileprivate var _storage = _StorageClass.defaultInstance @@ -2452,78 +2485,36 @@ extension Compiler_Protobuf_VariableDeclarator: SwiftProtobuf.Message, SwiftProt 2: .same(proto: "value"), ] - fileprivate class _StorageClass { - var _name: String = String() - var _value: Compiler_Protobuf_Expression? = nil - - #if swift(>=5.10) - // This property is used as the initial default value for new instances of the type. - // The type itself is protecting the reference to its storage via CoW semantics. - // This will force a copy to be made of this reference when the first mutation occurs; - // hence, it is safe to mark this as `nonisolated(unsafe)`. - static nonisolated(unsafe) let defaultInstance = _StorageClass() - #else - static let defaultInstance = _StorageClass() - #endif - - private init() {} - - init(copying source: _StorageClass) { - _name = source._name - _value = source._value - } - } - - fileprivate mutating func _uniqueStorage() -> _StorageClass { - if !isKnownUniquelyReferenced(&_storage) { - _storage = _StorageClass(copying: _storage) - } - return _storage - } - public mutating func decodeMessage(decoder: inout D) throws { - _ = _uniqueStorage() - try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - 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.decodeSingularStringField(value: &_storage._name) }() - case 2: try { try decoder.decodeSingularMessageField(value: &_storage._value) }() - default: break - } + 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.decodeSingularStringField(value: &self.name) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._value) }() + default: break } } } public func traverse(visitor: inout V) throws { - try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - // The use of inline closures is to circumvent an issue where the compiler - // 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 - if !_storage._name.isEmpty { - try visitor.visitSingularStringField(value: _storage._name, fieldNumber: 1) - } - try { if let v = _storage._value { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() + // The use of inline closures is to circumvent an issue where the compiler + // 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 + if !self.name.isEmpty { + try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) } + try { if let v = self._value { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Compiler_Protobuf_VariableDeclarator, rhs: Compiler_Protobuf_VariableDeclarator) -> Bool { - if lhs._storage !== rhs._storage { - let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in - let _storage = _args.0 - let rhs_storage = _args.1 - if _storage._name != rhs_storage._name {return false} - if _storage._value != rhs_storage._value {return false} - return true - } - if !storagesAreEqual {return false} - } + if lhs.name != rhs.name {return false} + if lhs._value != rhs._value {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -3740,13 +3731,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: "variableDeclaration"), + 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 @@ -3784,9 +3776,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_VariableDeclaration? + var hadOneofValue = false + if let current = _storage._left { + hadOneofValue = true + if case .variableDeclaration(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._left = .variableDeclaration(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 } } @@ -3799,14 +3816,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 .variableDeclaration?: try { + guard case .variableDeclaration(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) @@ -3832,13 +3857,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: "variableDeclaration"), + 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 @@ -3876,9 +3902,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_VariableDeclaration? + var hadOneofValue = false + if let current = _storage._left { + hadOneofValue = true + if case .variableDeclaration(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + _storage._left = .variableDeclaration(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 } } @@ -3891,14 +3942,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 .variableDeclaration?: try { + guard case .variableDeclaration(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 24559f24..d7844bc4 100644 --- a/Sources/Fuzzilli/Protobuf/ast.proto +++ b/Sources/Fuzzilli/Protobuf/ast.proto @@ -167,15 +167,21 @@ message ForLoop { } message ForInLoop { - VariableDeclarator left = 1; - Expression right = 2; - Statement body = 3; + oneof left { + VariableDeclaration variableDeclaration = 1; + Identifier identifier = 2; + } + Expression right = 3; + Statement body = 4; } message ForOfLoop { - VariableDeclarator left = 1; - Expression right = 2; - Statement body = 3; + oneof left { + VariableDeclaration variableDeclaration = 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 22c2008e..91c083e3 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -1,6 +1,5 @@ // DO NOT EDIT. // swift-format-ignore-file -// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: operations.proto @@ -22,6 +21,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -2319,7 +2319,21 @@ 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 variableName: String = String() + + public var declarationMode: Fuzzilli_Protobuf_NamedVariableDeclarationMode = .none + + 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. @@ -2339,7 +2353,21 @@ 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 variableName: String = String() + + public var declarationMode: Fuzzilli_Protobuf_NamedVariableDeclarationMode = .none + + 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. @@ -7150,8 +7178,46 @@ 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" +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 = [ + 1: .same(proto: "variableName"), + 2: .same(proto: "declarationMode"), + ] + + 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.decodeSingularStringField(value: &self.variableName) }() + case 2: try { try decoder.decodeSingularEnumField(value: &self.declarationMode) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.variableName.isEmpty { + try visitor.visitSingularStringField(value: self.variableName, fieldNumber: 1) + } + if self.declarationMode != .none { + try visitor.visitSingularEnumField(value: self.declarationMode, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginPlainForInLoop, rhs: Fuzzilli_Protobuf_BeginPlainForInLoop) -> Bool { + if lhs.variableName != rhs.variableName {return false} + if lhs.declarationMode != rhs.declarationMode {return false} + 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 { @@ -7163,7 +7229,7 @@ extension Fuzzilli_Protobuf_BeginForInLoop: SwiftProtobuf.Message, SwiftProtobuf try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginForInLoop, rhs: Fuzzilli_Protobuf_BeginForInLoop) -> Bool { + public static func ==(lhs: Fuzzilli_Protobuf_BeginForInLoopWithReassignment, rhs: Fuzzilli_Protobuf_BeginForInLoopWithReassignment) -> Bool { if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -7188,8 +7254,46 @@ 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" +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 = [ + 1: .same(proto: "variableName"), + 2: .same(proto: "declarationMode"), + ] + + 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.decodeSingularStringField(value: &self.variableName) }() + case 2: try { try decoder.decodeSingularEnumField(value: &self.declarationMode) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.variableName.isEmpty { + try visitor.visitSingularStringField(value: self.variableName, fieldNumber: 1) + } + if self.declarationMode != .none { + try visitor.visitSingularEnumField(value: self.declarationMode, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BeginPlainForOfLoop, rhs: Fuzzilli_Protobuf_BeginPlainForOfLoop) -> Bool { + if lhs.variableName != rhs.variableName {return false} + if lhs.declarationMode != rhs.declarationMode {return false} + 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 { @@ -7201,7 +7305,7 @@ extension Fuzzilli_Protobuf_BeginForOfLoop: SwiftProtobuf.Message, SwiftProtobuf try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Fuzzilli_Protobuf_BeginForOfLoop, rhs: Fuzzilli_Protobuf_BeginForOfLoop) -> Bool { + 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 c0dc359d..e1dee9c8 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -691,13 +691,23 @@ message BeginForLoopBody { message EndForLoop { } -message BeginForInLoop { +message BeginPlainForInLoop { + string variableName = 1; + NamedVariableDeclarationMode declarationMode = 2; +} + +message BeginForInLoopWithReassignment { } message EndForInLoop { } -message BeginForOfLoop { +message BeginPlainForOfLoop { + string variableName = 1; + NamedVariableDeclarationMode declarationMode = 2; +} + +message BeginForOfLoopWithReassignment { } message BeginForOfLoopWithDestruct { diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index 3e55f770..9af55ad1 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -1,6 +1,5 @@ // DO NOT EDIT. // swift-format-ignore-file -// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: program.proto @@ -1249,12 +1248,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 { @@ -1265,12 +1272,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 { @@ -1634,9 +1649,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) @@ -1863,35 +1880,37 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M 149: .same(proto: "beginForLoopAfterthought"), 150: .same(proto: "beginForLoopBody"), 151: .same(proto: "endForLoop"), - 152: .same(proto: "beginForInLoop"), - 153: .same(proto: "endForInLoop"), - 154: .same(proto: "beginForOfLoop"), - 155: .same(proto: "beginForOfLoopWithDestruct"), - 156: .same(proto: "endForOfLoop"), - 157: .same(proto: "beginRepeatLoop"), - 158: .same(proto: "endRepeatLoop"), - 159: .same(proto: "loopBreak"), - 160: .same(proto: "loopContinue"), - 161: .same(proto: "beginTry"), - 162: .same(proto: "beginCatch"), - 163: .same(proto: "beginFinally"), - 164: .same(proto: "endTryCatchFinally"), - 165: .same(proto: "throwException"), - 166: .same(proto: "beginCodeString"), - 167: .same(proto: "endCodeString"), - 168: .same(proto: "beginBlockStatement"), - 169: .same(proto: "endBlockStatement"), - 170: .same(proto: "beginSwitch"), - 171: .same(proto: "beginSwitchCase"), - 172: .same(proto: "beginSwitchDefaultCase"), - 173: .same(proto: "endSwitchCase"), - 174: .same(proto: "endSwitch"), - 175: .same(proto: "switchBreak"), - 176: .same(proto: "loadNewTarget"), - 177: .same(proto: "print"), - 178: .same(proto: "explore"), - 179: .same(proto: "probe"), - 180: .same(proto: "fixup"), + 152: .same(proto: "beginPlainForInLoop"), + 153: .same(proto: "beginForInLoopWithReassignment"), + 154: .same(proto: "endForInLoop"), + 155: .same(proto: "beginPlainForOfLoop"), + 156: .same(proto: "beginForOfLoopWithReassignment"), + 157: .same(proto: "beginForOfLoopWithDestruct"), + 158: .same(proto: "endForOfLoop"), + 159: .same(proto: "beginRepeatLoop"), + 160: .same(proto: "endRepeatLoop"), + 161: .same(proto: "loopBreak"), + 162: .same(proto: "loopContinue"), + 163: .same(proto: "beginTry"), + 164: .same(proto: "beginCatch"), + 165: .same(proto: "beginFinally"), + 166: .same(proto: "endTryCatchFinally"), + 167: .same(proto: "throwException"), + 168: .same(proto: "beginCodeString"), + 169: .same(proto: "endCodeString"), + 170: .same(proto: "beginBlockStatement"), + 171: .same(proto: "endBlockStatement"), + 172: .same(proto: "beginSwitch"), + 173: .same(proto: "beginSwitchCase"), + 174: .same(proto: "beginSwitchDefaultCase"), + 175: .same(proto: "endSwitchCase"), + 176: .same(proto: "endSwitch"), + 177: .same(proto: "switchBreak"), + 178: .same(proto: "loadNewTarget"), + 179: .same(proto: "print"), + 180: .same(proto: "explore"), + 181: .same(proto: "probe"), + 182: .same(proto: "fixup"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -3847,19 +3866,32 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M } }() case 152: 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 153: 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 154: try { var v: Fuzzilli_Protobuf_EndForInLoop? var hadOneofValue = false if let current = self.operation { @@ -3872,20 +3904,33 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForInLoop(v) } }() - case 154: try { - var v: Fuzzilli_Protobuf_BeginForOfLoop? + case 155: 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 155: try { + case 156: 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 157: try { var v: Fuzzilli_Protobuf_BeginForOfLoopWithDestruct? var hadOneofValue = false if let current = self.operation { @@ -3898,7 +3943,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginForOfLoopWithDestruct(v) } }() - case 156: try { + case 158: try { var v: Fuzzilli_Protobuf_EndForOfLoop? var hadOneofValue = false if let current = self.operation { @@ -3911,7 +3956,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endForOfLoop(v) } }() - case 157: try { + case 159: try { var v: Fuzzilli_Protobuf_BeginRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -3924,7 +3969,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginRepeatLoop(v) } }() - case 158: try { + case 160: try { var v: Fuzzilli_Protobuf_EndRepeatLoop? var hadOneofValue = false if let current = self.operation { @@ -3937,7 +3982,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endRepeatLoop(v) } }() - case 159: try { + case 161: try { var v: Fuzzilli_Protobuf_LoopBreak? var hadOneofValue = false if let current = self.operation { @@ -3950,7 +3995,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopBreak(v) } }() - case 160: try { + case 162: try { var v: Fuzzilli_Protobuf_LoopContinue? var hadOneofValue = false if let current = self.operation { @@ -3963,7 +4008,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopContinue(v) } }() - case 161: try { + case 163: try { var v: Fuzzilli_Protobuf_BeginTry? var hadOneofValue = false if let current = self.operation { @@ -3976,7 +4021,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginTry(v) } }() - case 162: try { + case 164: try { var v: Fuzzilli_Protobuf_BeginCatch? var hadOneofValue = false if let current = self.operation { @@ -3989,7 +4034,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCatch(v) } }() - case 163: try { + case 165: try { var v: Fuzzilli_Protobuf_BeginFinally? var hadOneofValue = false if let current = self.operation { @@ -4002,7 +4047,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginFinally(v) } }() - case 164: try { + case 166: try { var v: Fuzzilli_Protobuf_EndTryCatchFinally? var hadOneofValue = false if let current = self.operation { @@ -4015,7 +4060,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endTryCatchFinally(v) } }() - case 165: try { + case 167: try { var v: Fuzzilli_Protobuf_ThrowException? var hadOneofValue = false if let current = self.operation { @@ -4028,7 +4073,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .throwException(v) } }() - case 166: try { + case 168: try { var v: Fuzzilli_Protobuf_BeginCodeString? var hadOneofValue = false if let current = self.operation { @@ -4041,7 +4086,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginCodeString(v) } }() - case 167: try { + case 169: try { var v: Fuzzilli_Protobuf_EndCodeString? var hadOneofValue = false if let current = self.operation { @@ -4054,7 +4099,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endCodeString(v) } }() - case 168: try { + case 170: try { var v: Fuzzilli_Protobuf_BeginBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -4067,7 +4112,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginBlockStatement(v) } }() - case 169: try { + case 171: try { var v: Fuzzilli_Protobuf_EndBlockStatement? var hadOneofValue = false if let current = self.operation { @@ -4080,7 +4125,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endBlockStatement(v) } }() - case 170: try { + case 172: try { var v: Fuzzilli_Protobuf_BeginSwitch? var hadOneofValue = false if let current = self.operation { @@ -4093,7 +4138,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitch(v) } }() - case 171: try { + case 173: try { var v: Fuzzilli_Protobuf_BeginSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -4106,7 +4151,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchCase(v) } }() - case 172: try { + case 174: try { var v: Fuzzilli_Protobuf_BeginSwitchDefaultCase? var hadOneofValue = false if let current = self.operation { @@ -4119,7 +4164,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .beginSwitchDefaultCase(v) } }() - case 173: try { + case 175: try { var v: Fuzzilli_Protobuf_EndSwitchCase? var hadOneofValue = false if let current = self.operation { @@ -4132,7 +4177,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitchCase(v) } }() - case 174: try { + case 176: try { var v: Fuzzilli_Protobuf_EndSwitch? var hadOneofValue = false if let current = self.operation { @@ -4145,7 +4190,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .endSwitch(v) } }() - case 175: try { + case 177: try { var v: Fuzzilli_Protobuf_SwitchBreak? var hadOneofValue = false if let current = self.operation { @@ -4158,7 +4203,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .switchBreak(v) } }() - case 176: try { + case 178: try { var v: Fuzzilli_Protobuf_LoadNewTarget? var hadOneofValue = false if let current = self.operation { @@ -4171,7 +4216,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loadNewTarget(v) } }() - case 177: try { + case 179: try { var v: Fuzzilli_Protobuf_Print? var hadOneofValue = false if let current = self.operation { @@ -4184,7 +4229,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .print(v) } }() - case 178: try { + case 180: try { var v: Fuzzilli_Protobuf_Explore? var hadOneofValue = false if let current = self.operation { @@ -4197,7 +4242,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .explore(v) } }() - case 179: try { + case 181: try { var v: Fuzzilli_Protobuf_Probe? var hadOneofValue = false if let current = self.operation { @@ -4210,7 +4255,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .probe(v) } }() - case 180: try { + case 182: try { var v: Fuzzilli_Protobuf_Fixup? var hadOneofValue = false if let current = self.operation { @@ -4837,121 +4882,129 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .endForLoop(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 151) }() - 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: 152) }() - 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: 153) }() - 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: 154) }() + case .beginPlainForOfLoop?: try { + guard case .beginPlainForOfLoop(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 155) + }() + case .beginForOfLoopWithReassignment?: try { + guard case .beginForOfLoopWithReassignment(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 156) + }() case .beginForOfLoopWithDestruct?: try { guard case .beginForOfLoopWithDestruct(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 155) + try visitor.visitSingularMessageField(value: v, fieldNumber: 157) }() case .endForOfLoop?: try { guard case .endForOfLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 156) + try visitor.visitSingularMessageField(value: v, fieldNumber: 158) }() case .beginRepeatLoop?: try { guard case .beginRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 157) + try visitor.visitSingularMessageField(value: v, fieldNumber: 159) }() case .endRepeatLoop?: try { guard case .endRepeatLoop(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 158) + try visitor.visitSingularMessageField(value: v, fieldNumber: 160) }() case .loopBreak?: try { guard case .loopBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 159) + try visitor.visitSingularMessageField(value: v, fieldNumber: 161) }() case .loopContinue?: try { guard case .loopContinue(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 160) + try visitor.visitSingularMessageField(value: v, fieldNumber: 162) }() case .beginTry?: try { guard case .beginTry(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 161) + try visitor.visitSingularMessageField(value: v, fieldNumber: 163) }() case .beginCatch?: try { guard case .beginCatch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 162) + try visitor.visitSingularMessageField(value: v, fieldNumber: 164) }() case .beginFinally?: try { guard case .beginFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 163) + try visitor.visitSingularMessageField(value: v, fieldNumber: 165) }() case .endTryCatchFinally?: try { guard case .endTryCatchFinally(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 164) + try visitor.visitSingularMessageField(value: v, fieldNumber: 166) }() case .throwException?: try { guard case .throwException(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 165) + try visitor.visitSingularMessageField(value: v, fieldNumber: 167) }() case .beginCodeString?: try { guard case .beginCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 166) + try visitor.visitSingularMessageField(value: v, fieldNumber: 168) }() case .endCodeString?: try { guard case .endCodeString(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 167) + try visitor.visitSingularMessageField(value: v, fieldNumber: 169) }() case .beginBlockStatement?: try { guard case .beginBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 168) + try visitor.visitSingularMessageField(value: v, fieldNumber: 170) }() case .endBlockStatement?: try { guard case .endBlockStatement(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 169) + try visitor.visitSingularMessageField(value: v, fieldNumber: 171) }() case .beginSwitch?: try { guard case .beginSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 170) + try visitor.visitSingularMessageField(value: v, fieldNumber: 172) }() case .beginSwitchCase?: try { guard case .beginSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 171) + try visitor.visitSingularMessageField(value: v, fieldNumber: 173) }() case .beginSwitchDefaultCase?: try { guard case .beginSwitchDefaultCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 172) + try visitor.visitSingularMessageField(value: v, fieldNumber: 174) }() case .endSwitchCase?: try { guard case .endSwitchCase(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 173) + try visitor.visitSingularMessageField(value: v, fieldNumber: 175) }() case .endSwitch?: try { guard case .endSwitch(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 174) + try visitor.visitSingularMessageField(value: v, fieldNumber: 176) }() case .switchBreak?: try { guard case .switchBreak(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 175) + try visitor.visitSingularMessageField(value: v, fieldNumber: 177) }() case .loadNewTarget?: try { guard case .loadNewTarget(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 176) + try visitor.visitSingularMessageField(value: v, fieldNumber: 178) }() case .print?: try { guard case .print(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 177) + try visitor.visitSingularMessageField(value: v, fieldNumber: 179) }() case .explore?: try { guard case .explore(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 178) + try visitor.visitSingularMessageField(value: v, fieldNumber: 180) }() case .probe?: try { guard case .probe(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 179) + try visitor.visitSingularMessageField(value: v, fieldNumber: 181) }() case .fixup?: try { guard case .fixup(let v)? = self.operation else { preconditionFailure() } - try visitor.visitSingularMessageField(value: v, fieldNumber: 180) + try visitor.visitSingularMessageField(value: v, fieldNumber: 182) }() case nil: break } diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 918affd6..39a09402 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -175,35 +175,37 @@ message Instruction { BeginForLoopAfterthought beginForLoopAfterthought = 149; BeginForLoopBody beginForLoopBody = 150; EndForLoop endForLoop = 151; - BeginForInLoop beginForInLoop = 152; - EndForInLoop endForInLoop = 153; - BeginForOfLoop beginForOfLoop = 154; - BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 155; - EndForOfLoop endForOfLoop = 156; - BeginRepeatLoop beginRepeatLoop = 157; - EndRepeatLoop endRepeatLoop = 158; - LoopBreak loopBreak = 159; - LoopContinue loopContinue = 160; - BeginTry beginTry = 161; - BeginCatch beginCatch = 162; - BeginFinally beginFinally = 163; - EndTryCatchFinally endTryCatchFinally = 164; - ThrowException throwException = 165; - BeginCodeString beginCodeString = 166; - EndCodeString endCodeString = 167; - BeginBlockStatement beginBlockStatement = 168; - EndBlockStatement endBlockStatement = 169; - BeginSwitch beginSwitch = 170; - BeginSwitchCase beginSwitchCase = 171; - BeginSwitchDefaultCase beginSwitchDefaultCase = 172; - EndSwitchCase endSwitchCase = 173; - EndSwitch endSwitch = 174; - SwitchBreak switchBreak = 175; - LoadNewTarget loadNewTarget = 176; - Print print = 177; - Explore explore = 178; - Probe probe = 179; - Fixup fixup = 180; + BeginPlainForInLoop beginPlainForInLoop = 152; + BeginForInLoopWithReassignment beginForInLoopWithReassignment = 153; + EndForInLoop endForInLoop = 154; + BeginPlainForOfLoop beginPlainForOfLoop = 155; + BeginForOfLoopWithReassignment beginForOfLoopWithReassignment = 156; + BeginForOfLoopWithDestruct beginForOfLoopWithDestruct = 157; + EndForOfLoop endForOfLoop = 158; + BeginRepeatLoop beginRepeatLoop = 159; + EndRepeatLoop endRepeatLoop = 160; + LoopBreak loopBreak = 161; + LoopContinue loopContinue = 162; + BeginTry beginTry = 163; + BeginCatch beginCatch = 164; + BeginFinally beginFinally = 165; + EndTryCatchFinally endTryCatchFinally = 166; + ThrowException throwException = 167; + BeginCodeString beginCodeString = 168; + EndCodeString endCodeString = 169; + BeginBlockStatement beginBlockStatement = 170; + EndBlockStatement endBlockStatement = 171; + BeginSwitch beginSwitch = 172; + BeginSwitchCase beginSwitchCase = 173; + BeginSwitchDefaultCase beginSwitchDefaultCase = 174; + EndSwitchCase endSwitchCase = 175; + EndSwitch endSwitch = 176; + SwitchBreak switchBreak = 177; + LoadNewTarget loadNewTarget = 178; + Print print = 179; + Explore explore = 180; + Probe probe = 181; + Fixup fixup = 182; } } diff --git a/Sources/Fuzzilli/Protobuf/sync.pb.swift b/Sources/Fuzzilli/Protobuf/sync.pb.swift index ec48a9ca..156ed692 100644 --- a/Sources/Fuzzilli/Protobuf/sync.pb.swift +++ b/Sources/Fuzzilli/Protobuf/sync.pb.swift @@ -1,6 +1,5 @@ // DO NOT EDIT. // swift-format-ignore-file -// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: sync.proto diff --git a/Tests/FuzzilliTests/AnalyzerTest.swift b/Tests/FuzzilliTests/AnalyzerTest.swift index 4bffb5cd..4ebe8f97 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], "foo", declarationMode: .const) { _ 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], "foo", declarationMode: .const) { _ 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/CompilerTests/advanced_loops.js b/Tests/FuzzilliTests/CompilerTests/advanced_loops.js index 7f40a8bf..c3c5f810 100644 --- a/Tests/FuzzilliTests/CompilerTests/advanced_loops.js +++ b/Tests/FuzzilliTests/CompilerTests/advanced_loops.js @@ -1,91 +1,65 @@ -if (typeof output === 'undefined') output = console.log; +var foo = 0 +console.log(foo) +// ------------------ Plain For-of loops ------------------ +for (const a of ["a"]) {} +for (let b of ["b"]) {} +for (var c of ["c"]) {} +for (d of ["d"]) {} -let counter = 5; -function countdown() { - return counter--; -} -function resetCounter() { - counter = 5; -} +try {foo = a } +catch (err) { console.log("Test 1 successful");} +try {foo = b } +catch (err) { console.log("Test 2 successful");} +if (c === "c") console.log("Test 3 successful"); +if (d === "d") console.log("Test 4 successful"); -// -// While loops -// -while (countdown()) { - output("inside while loop body"); -} -resetCounter() +// --------------- Reassigning For-of loops --------------- -while (output("inside while loop header"), output("still inside while loop header"), countdown()) { - output("inside while loop body"); -} -resetCounter(); +const e = "e"; +let f = "f"; +var g = "g"; +h = "h"; -while (output("inside while loop header"), counter) { - output("inside while loop body"); - countdown(); -} -resetCounter(); +try { for (e of ["e_new"]) {} } +catch (err) { console.log("Test 5 successful");} // can not reassign const +for (f of ["f_new"]) {} +for (g of ["g_new"]) {} +for (h of ["h_new"]) {} -while ((function() { let c = countdown(); output("inside temporary function, c = " + c); return c; })()) { - output("inside while loop body"); -} -resetCounter(); +if (e == "e") console.log("Test 6 successful"); +if (f == "f_new") console.log("Test 7 successful"); +if (g == "g_new") console.log("Test 8 successful"); +if (h == "h_new") console.log("Test 9 successful"); -// -// Do-While loops -// -do { - output("inside do-while loop body"); -} while (countdown()) -resetCounter() +// ------------------ Plain For-in loops ------------------ -do { - output("inside do-while loop body"); -} while (output("inside do-while loop header"), output("still inside do-while loop header"), countdown()) -resetCounter(); -do { - output("inside do-while loop body"); - countdown(); -} while (output("inside do-while loop header"), counter) -resetCounter(); +for (const i in ["i"]) {} +for (let j in ["j"]) {} +for (var k in ["k"]) {} +for (l in ["l"]) {} -do { - output("inside do-while loop body"); -} while ((function() { let c = countdown(); output("inside temporary function, c = " + c); return c; })()) -resetCounter(); +try {foo = i } +catch (err) { console.log("Test 10 successful");} +try {foo = j } +catch (err) { console.log("Test 11 successful");} +if (k === "0") console.log("Test 12 successful"); +if (l === "0") console.log("Test 13 successful"); +// --------------- Reassigning For-in loops --------------- -// -// For loops -// -for (;;) { - if (!counter--) { - break; - } - output("inside for loop body"); - continue; - output("should not be reached"); -} -resetCounter(); +const m = "m"; +let n = "n"; +var o = "o"; +p = "p"; -for (let i = 0, j = 10; i < j; i++, j--) { - output("inside for loop body, i: " + i + " j: " + j); -} +try { for (m in ["m_new"]) {} } +catch (err) { console.log("Test 14 successful");} +for (n in ["n_new"]) {} +for (o in ["o_new"]) {} +for (p in ["p_new"]) {} -for (; countdown();) { - output("inside for loop body"); -} -resetCounter(); - -for (let i = 0; ; i++) { - output("inside for loop body"); - if (i >= 5) break; -} - -for (output("inside for loop initializer"); output("inside for loop condition"), true; output("inside for loop afterthought")) { - output("inside for loop body"); - if (!countdown()) break; -} -resetCounter(); +if (m == "m") console.log("Test 15 successful"); +if (n != "n") console.log("Test 16 successful"); +if (o != "o") console.log("Test 17 successful"); +if (p != "p") console.log("Test 18 successful"); diff --git a/Tests/FuzzilliTests/JSTyperTests.swift b/Tests/FuzzilliTests/JSTyperTests.swift index a56a1d67..24e86aed 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, "foo", declarationMode: .const) { loopVar in XCTAssertEqual(b.type(of: loopVar), .string) body() } case 3: - b.buildForOfLoop(obj) { loopVar in + b.buildPlainForOfLoop(obj, "foo", declarationMode: .const) { loopVar in XCTAssertEqual(b.type(of: loopVar), .anything) body() } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 1f10e12a..1828e50d 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -2709,9 +2709,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.createNamedVariable(forBuiltin: "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], "bar", declarationMode: .const) { v in b.callFunction(print, withArgs: [v]) } } @@ -2722,8 +2722,8 @@ class LifterTests: XCTestCase { let expected = """ for (let [v17,,...v18] of [[10,11,12,13,14],[20,21,22,23],[30,31,32]]) { print(v17); - for (const v20 of v18) { - print(v20); + for (const bar of v18) { + print(bar); } } @@ -2732,13 +2732,38 @@ 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 v1 = { x: 42 }; + let v2 = "initial"; + for (v2 in v1) { + 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, "foo", declarationMode: .let) { v2 in b.blockStatement { let v3 = b.loadInt(1337) b.reassign(v2, to: v3) @@ -2755,11 +2780,11 @@ class LifterTests: XCTestCase { let expected = """ const v1 = { a: 1337 }; - for (let v2 in v1) { + for (let foo in v1) { { - v2 = 1337; + foo = 1337; { - v2 = { a: v1 }; + foo = { a: v1 }; } } } diff --git a/Tests/FuzzilliTests/ProgramBuilderTest.swift b/Tests/FuzzilliTests/ProgramBuilderTest.swift index 4dfe07a5..50b1c011 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, "foo", declarationMode: .const) { 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, "foo", declarationMode: .const) { p in let i = b.loadInt(1337) b.loadString("unusedButPartOfBody") b.setComputedProperty(p, of: o2, to: i)