From 17edc6b067a635455450b26ec230b3c1eae8398e Mon Sep 17 00:00:00 2001 From: Yi2255 Date: Wed, 30 Apr 2025 09:33:54 +0000 Subject: [PATCH 1/2] feature/loopNestedContinue --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 4 + .../CodeGen/CodeGeneratorWeights.swift | 1 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 6 +- Sources/Fuzzilli/FuzzIL/Instruction.swift | 4 + Sources/Fuzzilli/FuzzIL/JsOperations.swift | 13 +- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 1 + Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 3 + .../Fuzzilli/Lifting/JavaScriptLifter.swift | 121 ++++++++++++++++++ Sources/Fuzzilli/Lifting/ScriptWriter.swift | 8 ++ .../Fuzzilli/Mutators/OperationMutator.swift | 2 + Sources/Fuzzilli/Protobuf/operations.pb.swift | 34 +++++ Sources/Fuzzilli/Protobuf/operations.proto | 3 + Sources/Fuzzilli/Protobuf/program.pb.swift | 28 +++- Sources/Fuzzilli/Protobuf/program.proto | 1 + Sources/Fuzzilli/Util/MockFuzzer.swift | 1 + Tests/FuzzilliTests/LifterTest.swift | 35 ++++- 16 files changed, 260 insertions(+), 5 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 0df465c17..a108888e2 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2822,6 +2822,10 @@ public class ProgramBuilder { emit(Print(), withInputs: [value]) } + public func loopNestedContinue(_ depth: Int){ + emit(LoopNestedContinue(depth), withInputs: []) + } + @discardableResult public func createWasmGlobal(value: WasmGlobal, isMutable: Bool) -> Variable { diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 54dc9efc8..823ec676d 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -169,6 +169,7 @@ public let codeGeneratorWeights = [ "TryCatchGenerator": 5, "ThrowGenerator": 1, "BlockStatementGenerator": 1, + "LoopNestedContinueGenerator": 1, // Special generators "WellKnownPropertyLoadGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index fdb9bc330..55ff3c336 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -54,7 +54,7 @@ public let CodeGenerators: [CodeGenerator] = [ ValueGenerator("StringGenerator") { b, n in for _ in 0.. Void) { + body(&writer) + } } // Helper class for formatting object literals. @@ -2268,4 +2304,89 @@ public class JavaScriptLifter: Lifter { fields[fields.count - 1] += body + "}" } } + + // Every possible position of label + struct LabelPin { + var beginPos: Int + var hasLabel: Bool + } + + enum LabelType { + case loopblock + case ifblock + case switchblock + case tryblock + case codeBlock + case withblock + } + + /// A structure that manages label positions within a specific control flow block (e.g., loop, if, switch, etc.). + public struct LabelStack { + let type: LabelType + + private var stack: [LabelPin] = [] + + init(type: LabelType) { + self.type = type + } + + /// Records a new label pin at the current code position. + mutating func push(currentCodeLength: Int) { + stack.append(LabelPin(beginPos: currentCodeLength, hasLabel: false)) + } + + /// Removes the most recently recorded label pin. + mutating func pop() { + _ = stack.popLast() + } + + /// Checks whether a label has already been inserted at the specified index. + func labelExists(at index: Int) -> Bool { + return stack[index].hasLabel + } + + /// Updates the label stack when a label is inserted into the code. + /// + /// This method: + /// - Marks the label at the specified index as inserted. + /// - Inserts the label content at the given code position. + /// - Shifts the positions of subsequent labels accordingly. + mutating func insertLabel(writer: inout ScriptWriter, at index: Int, labelContent: String) { + guard index < stack.count else { return } + + let insertPos = stack[index].beginPos + writer.insert(insertPos, labelContent) + + stack[index].hasLabel = true + + let delta = labelContent.count + for i in index+1.. Int{ + return stack.count + } + } } diff --git a/Sources/Fuzzilli/Lifting/ScriptWriter.swift b/Sources/Fuzzilli/Lifting/ScriptWriter.swift index d5bf5a38c..df76cc4f5 100644 --- a/Sources/Fuzzilli/Lifting/ScriptWriter.swift +++ b/Sources/Fuzzilli/Lifting/ScriptWriter.swift @@ -84,4 +84,12 @@ struct ScriptWriter { assert(currentIndention.count >= indent.count) currentIndention.removeLast(indent.count) } + + mutating func insert(_ pos: Int, _ content: String){ + if code.index(code.startIndex, offsetBy: pos, limitedBy: code.endIndex) != nil { + let index = code.index(code.startIndex, offsetBy: pos) + code.insert(contentsOf: content, at: index) + currentLineNumber += 1 + } + } } diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index 740d35967..f241192cd 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -221,6 +221,8 @@ public class OperationMutator: BaseInstructionMutator { newOp = UpdateSuperProperty(propertyName: b.randomPropertyName(), operator: chooseUniform(from: BinaryOperator.allCases)) case .beginIf(let op): newOp = BeginIf(inverted: !op.inverted) + case .loopNestedContinue(let op): + newOp = LoopNestedContinue(Int.random(in: 0...10)) case .createWasmGlobal(let op): // The type has to match for wasm, we cannot just switch types here as the rest of the wasm code will become invalid. // TODO: add nullref and funcref as types here. diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 0efd2ada8..7552c7f3c 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -2922,6 +2922,7 @@ public struct Fuzzilli_Protobuf_LoopContinue: Sendable { public init() {} } + public struct Fuzzilli_Protobuf_BeginTry: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -3012,6 +3013,7 @@ public struct Fuzzilli_Protobuf_EndBlockStatement: Sendable { public init() {} } + public struct Fuzzilli_Protobuf_Nop: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -3032,6 +3034,18 @@ public struct Fuzzilli_Protobuf_Print: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_LoopNestedContinue: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + public struct Fuzzilli_Protobuf_BeginWasmModule: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -9502,6 +9516,7 @@ extension Fuzzilli_Protobuf_EndBlockStatement: SwiftProtobuf.Message, SwiftProto } } + extension Fuzzilli_Protobuf_Nop: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Nop" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -9540,6 +9555,25 @@ extension Fuzzilli_Protobuf_Print: SwiftProtobuf.Message, SwiftProtobuf._Message } } +extension Fuzzilli_Protobuf_LoopNestedContinue: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".LoopNestedContinue" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_LoopNestedContinue, rhs: Fuzzilli_Protobuf_LoopNestedContinue) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginWasmModule: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginWasmModule" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index e9ae34bf2..3afcd258c 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1220,6 +1220,9 @@ message WasmSelect { WasmILType type = 1; } +message LoopNestedContinue { +} + message ConstSimd128 { repeated uint32 value = 1; } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index eeaa73cf4..b487bb643 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2257,6 +2257,14 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .wasmSelect(newValue)} } + public var loopNestedContinue: Fuzzilli_Protobuf_LoopNestedContinue { + get { + if case .loopNestedContinue(let v)? = operation {return v} + return Fuzzilli_Protobuf_LoopNestedContinue() + } + set {operation = .loopNestedContinue(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -2536,7 +2544,7 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmSimdLoad(Fuzzilli_Protobuf_WasmSimdLoad) case wasmUnreachable(Fuzzilli_Protobuf_WasmUnreachable) case wasmSelect(Fuzzilli_Protobuf_WasmSelect) - + case loopNestedContinue(Fuzzilli_Protobuf_LoopNestedContinue) } public init() {} @@ -2862,6 +2870,7 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M 275: .same(proto: "wasmSimdLoad"), 276: .same(proto: "wasmUnreachable"), 277: .same(proto: "wasmSelect"), + 278: .same(proto: "loopNestedContinue"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -6454,6 +6463,19 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .wasmSelect(v) } }() + case 278: try { + var v: Fuzzilli_Protobuf_LoopNestedContinue? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .loopNestedContinue(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .loopNestedContinue(v) + } + }() default: break } } @@ -7572,6 +7594,10 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M guard case .wasmSelect(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 277) }() + case .loopNestedContinue?: try { + guard case .loopNestedContinue(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 284) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index c3bd42a18..8adcb7317 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -301,6 +301,7 @@ message Instruction { WasmSimdLoad wasmSimdLoad = 275; WasmUnreachable wasmUnreachable = 276; WasmSelect wasmSelect = 277; + LoopNestedContinue loopNestedContinue = 278; } } diff --git a/Sources/Fuzzilli/Util/MockFuzzer.swift b/Sources/Fuzzilli/Util/MockFuzzer.swift index 465f64a99..1a3ac4fdd 100644 --- a/Sources/Fuzzilli/Util/MockFuzzer.swift +++ b/Sources/Fuzzilli/Util/MockFuzzer.swift @@ -219,6 +219,7 @@ public func makeMockFuzzer(config maybeConfiguration: Configuration? = nil, engi // Use all builtin CodeGenerators let codeGenerators = WeightedList(CodeGenerators.map { return ($0, codeGeneratorWeights[$0.name]!) } + WasmCodeGenerators.map { return ($0, codeGeneratorWeights[$0.name]!) }) + // Use all builtin ProgramTemplates let programTemplates = WeightedList(ProgramTemplates.map { return ($0, programTemplateWeights[$0.name]!) }) diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index 8c421c281..cffd10e06 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -2790,7 +2790,7 @@ class LifterTests: XCTestCase { XCTAssertEqual(actual, expected) } - + func testSingularOperationLifting() { let fuzzer = makeMockFuzzer() let b = fuzzer.makeBuilder() @@ -3095,4 +3095,35 @@ class LifterTests: XCTestCase { """ XCTAssertEqual(actual, expected) } -} + + func testLoopNestedContinueLifting(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildRepeatLoop(n: 10) { + b.buildRepeatLoop(n: 10) { + b.buildRepeatLoop(n: 10) { + b.loopNestedContinue(2) + } + b.loopNestedContinue(1) + } + } + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + let expected = """ + for (let i = 0; i < 10; i++) { + label1: + for (let i = 0; i < 10; i++) { + label2: + for (let i = 0; i < 10; i++) { + continue label2; + } + continue label1; + } + } + + """ + XCTAssertEqual(actual, expected) + } + +} \ No newline at end of file From 6169ed9eb7b104dd4cef05cbe4b356502cb181d4 Mon Sep 17 00:00:00 2001 From: Yi2255 Date: Wed, 30 Apr 2025 10:31:23 +0000 Subject: [PATCH 2/2] feature/NestedBreak --- Sources/Fuzzilli/Base/ProgramBuilder.swift | 24 + .../CodeGen/CodeGeneratorWeights.swift | 6 + Sources/Fuzzilli/CodeGen/CodeGenerators.swift | 26 +- Sources/Fuzzilli/FuzzIL/Context.swift | 6 + Sources/Fuzzilli/FuzzIL/Instruction.swift | 24 + Sources/Fuzzilli/FuzzIL/JsOperations.swift | 73 ++- Sources/Fuzzilli/FuzzIL/Opcodes.swift | 6 + Sources/Fuzzilli/Lifting/FuzzILLifter.swift | 18 + .../Fuzzilli/Lifting/JavaScriptLifter.swift | 45 ++ .../Fuzzilli/Mutators/OperationMutator.swift | 12 + Sources/Fuzzilli/Protobuf/operations.pb.swift | 183 +++++++ Sources/Fuzzilli/Protobuf/operations.proto | 18 + Sources/Fuzzilli/Protobuf/program.pb.swift | 164 ++++++ Sources/Fuzzilli/Protobuf/program.proto | 6 + Tests/FuzzilliTests/LifterTest.swift | 514 +++++++++++++++++- 15 files changed, 1117 insertions(+), 8 deletions(-) diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index a108888e2..e3c38381c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2826,6 +2826,30 @@ public class ProgramBuilder { emit(LoopNestedContinue(depth), withInputs: []) } + public func loopNestedBreak(_ depth: Int){ + emit(LoopNestedBreak(depth), withInputs: []) + } + + public func blockNestedBreak(_ depth: Int){ + emit(BlockNestedBreak(depth), withInputs: []) + } + + public func ifNestedBreak(_ depth: Int){ + emit(IfNestedBreak(depth), withInputs: []) + } + + public func switchNestedBreak(_ depth: Int){ + emit(SwitchNestedBreak(depth), withInputs: []) + } + + public func withNestedBreak(_ depth: Int){ + emit(WithNestedBreak(depth), withInputs: []) + } + + public func tryNestedBreak(_ depth: Int){ + emit(TryNestedBreak(depth), withInputs: []) + } + @discardableResult public func createWasmGlobal(value: WasmGlobal, isMutable: Bool) -> Variable { diff --git a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift index 823ec676d..6e5f61a55 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -170,6 +170,12 @@ public let codeGeneratorWeights = [ "ThrowGenerator": 1, "BlockStatementGenerator": 1, "LoopNestedContinueGenerator": 1, + "LoopNestedBreakGenerator": 1, + "BlockNestedBreakGenerator": 1, + "IfNestedBreakGenerator": 1, + "TryNestedBreakGenerator": 1, + "SwitchNestedBreakGenerator": 1, + "WithNestedBreakGenerator": 1, // Special generators "WellKnownPropertyLoadGenerator": 5, diff --git a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift index 55ff3c336..8acb19a10 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGenerators.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGenerators.swift @@ -1869,7 +1869,31 @@ public let CodeGenerators: [CodeGenerator] = [ CodeGenerator("LoopNestedContinueGenerator", inContext: .loop) { b in b.loopNestedContinue(Int.random(in: 0...10)) - } + }, + + CodeGenerator("LoopNestedBreakGenerator", inContext: .loop) { b in + b.loopNestedBreak(Int.random(in: 0...10)) + }, + + CodeGenerator("BlockNestedBreakGenerator", inContext: .codeBlock) { b in + b.blockNestedBreak(Int.random(in: 0...10)) + }, + + CodeGenerator("IfNestedBreakGenerator", inContext: .ifBlock) { b in + b.ifNestedBreak(Int.random(in: 0...10)) + }, + + CodeGenerator("TryNestedBreakGenerator", inContext: .tryBlock) { b in + b.tryNestedBreak(Int.random(in: 0...10)) + }, + + CodeGenerator("SwitchNestedBreakGenerator", inContext: .switchBlock) { b in + b.switchNestedBreak(Int.random(in: 0...10)) + }, + + CodeGenerator("WithNestedBreakGenerator", inContext: .with) { b in + b.withNestedBreak(Int.random(in: 0...10)) + }, ] extension Array where Element == CodeGenerator { diff --git a/Sources/Fuzzilli/FuzzIL/Context.swift b/Sources/Fuzzilli/FuzzIL/Context.swift index 38596c06f..d2913d010 100644 --- a/Sources/Fuzzilli/FuzzIL/Context.swift +++ b/Sources/Fuzzilli/FuzzIL/Context.swift @@ -55,6 +55,12 @@ public struct Context: OptionSet { public static let wasmFunction = Context(rawValue: 1 << 13) // Inside a block of a wasm function, allows branches public static let wasmBlock = Context(rawValue: 1 << 14) + // Inside a block + public static let codeBlock = Context(rawValue: 1 << 15) + // Inside a if|else block + public static let ifBlock = Context(rawValue: 1 << 16) + // Inside a try|catch block + public static let tryBlock = Context(rawValue: 1 << 17) public static let empty = Context([]) diff --git a/Sources/Fuzzilli/FuzzIL/Instruction.swift b/Sources/Fuzzilli/FuzzIL/Instruction.swift index 7a1cb7f87..922665f69 100644 --- a/Sources/Fuzzilli/FuzzIL/Instruction.swift +++ b/Sources/Fuzzilli/FuzzIL/Instruction.swift @@ -1032,6 +1032,18 @@ extension Instruction: ProtobufConvertible { $0.bindMethod = Fuzzilli_Protobuf_BindMethod.with { $0.methodName = op.methodName } case .loopNestedContinue: $0.loopNestedContinue = Fuzzilli_Protobuf_LoopNestedContinue() + case .loopNestedBreak: + $0.loopNestedBreak = Fuzzilli_Protobuf_LoopNestedBreak() + case .blockNestedBreak: + $0.blockNestedBreak = Fuzzilli_Protobuf_BlockNestedBreak() + case .ifNestedBreak: + $0.ifNestedBreak = Fuzzilli_Protobuf_IfNestedBreak() + case .tryNestedBreak: + $0.tryNestedBreak = Fuzzilli_Protobuf_TryNestedBreak() + case .switchNestedBreak: + $0.switchNestedBreak = Fuzzilli_Protobuf_SwitchNestedBreak() + case .withNestedBreak: + $0.withNestedBreak = Fuzzilli_Protobuf_WithNestedBreak() case .print(_): fatalError("Print operations should not be serialized") // Wasm Operations @@ -1896,6 +1908,18 @@ extension Instruction: ProtobufConvertible { op = Nop() case .loopNestedContinue(let d): op = LoopNestedContinue(d.depth) + case .loopNestedBreak(let d): + op = LoopNestedBreak(d.depth) + case .blockNestedBreak(let d): + op = BlockNestedBreak(d.depth) + case .ifNestedBreak(let d): + op = IfNestedBreak(d.depth) + case .tryNestedBreak(let d): + op = TryNestedBreak(d.depth) + case .switchNestedBreak(let d): + op = SwitchNestedBreak(d.depth) + case .withNestedBreak(let d): + op = WithNestedBreak(d.depth) case .createWasmGlobal(let p): op = CreateWasmGlobal(value: convertWasmGlobal(p.wasmGlobal), isMutable: p.wasmGlobal.isMutable) case .createWasmMemory(let p): diff --git a/Sources/Fuzzilli/FuzzIL/JsOperations.swift b/Sources/Fuzzilli/FuzzIL/JsOperations.swift index 2b7cd19f2..1b0e49fcc 100644 --- a/Sources/Fuzzilli/FuzzIL/JsOperations.swift +++ b/Sources/Fuzzilli/FuzzIL/JsOperations.swift @@ -1945,7 +1945,7 @@ final class BeginIf: JsOperation { init(inverted: Bool) { self.inverted = inverted - super.init(numInputs: 1, attributes: [.isBlockStart, .isMutable, .propagatesSurroundingContext], contextOpened: .javascript) + super.init(numInputs: 1, attributes: [.isBlockStart, .isMutable, .propagatesSurroundingContext], contextOpened: [.javascript, .ifBlock]) } } @@ -1953,7 +1953,7 @@ final class BeginElse: JsOperation { override var opcode: Opcode { .beginElse(self) } init() { - super.init(attributes: [.isBlockEnd, .isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init(attributes: [.isBlockEnd, .isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .ifBlock]) } } @@ -2234,7 +2234,7 @@ final class BeginTry: JsOperation { override var opcode: Opcode { .beginTry(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext]) + super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .tryBlock]) } } @@ -2242,7 +2242,7 @@ final class BeginCatch: JsOperation { override var opcode: Opcode { .beginCatch(self) } init() { - super.init(numInnerOutputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext]) + super.init(numInnerOutputs: 1, attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .tryBlock]) } } @@ -2250,7 +2250,7 @@ final class BeginFinally: JsOperation { override var opcode: Opcode { .beginFinally(self) } init() { - super.init(attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext]) + super.init(attributes: [.isBlockStart, .isBlockEnd, .propagatesSurroundingContext], contextOpened: [.javascript, .tryBlock]) } } @@ -2292,7 +2292,7 @@ final class BeginBlockStatement: JsOperation { override var opcode: Opcode { .beginBlockStatement(self) } init() { - super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: .javascript) + super.init(attributes: [.isBlockStart, .propagatesSurroundingContext], contextOpened: [.javascript, .codeBlock]) } } @@ -2475,6 +2475,67 @@ final class LoopNestedContinue: JsOperation { } } +final class LoopNestedBreak: JsOperation { + override var opcode: Opcode { .loopNestedBreak(self) } + + let depth: Int + + init(_ depth: Int) { + self.depth = depth + super.init(attributes: [.isJump], requiredContext: [.javascript, .loop]) + } +} +final class BlockNestedBreak: JsOperation { + override var opcode: Opcode { .blockNestedBreak(self) } + + let depth: Int + + init(_ depth: Int) { + self.depth = depth + super.init(attributes: [.isJump], requiredContext: [.javascript, .codeBlock]) + } +} +final class IfNestedBreak: JsOperation { + override var opcode: Opcode { .ifNestedBreak(self) } + + let depth: Int + + init(_ depth: Int) { + self.depth = depth + super.init(attributes: [.isJump], requiredContext: [.javascript, .ifBlock]) + } +} +final class TryNestedBreak: JsOperation { + override var opcode: Opcode { .tryNestedBreak(self) } + + let depth: Int + + init(_ depth: Int) { + self.depth = depth + super.init(attributes: [.isJump], requiredContext: [.javascript, .tryBlock]) + } +} +final class SwitchNestedBreak: JsOperation { + override var opcode: Opcode { .switchNestedBreak(self) } + + let depth: Int + + init(_ depth: Int) { + self.depth = depth + super.init(attributes: [.isJump], requiredContext: [.javascript, .switchCase]) + } +} +final class WithNestedBreak: JsOperation { + override var opcode: Opcode { .withNestedBreak(self) } + + let depth: Int + + init(_ depth: Int) { + self.depth = depth + super.init(attributes: [.isJump], requiredContext: [.javascript, .with]) + } +} + // This instruction is used to create strongly typed WasmGlobals in the JS world that can be imported by a WasmModule. class CreateWasmGlobal: JsOperation { diff --git a/Sources/Fuzzilli/FuzzIL/Opcodes.swift b/Sources/Fuzzilli/FuzzIL/Opcodes.swift index 9ebcff71b..d2125c1a7 100644 --- a/Sources/Fuzzilli/FuzzIL/Opcodes.swift +++ b/Sources/Fuzzilli/FuzzIL/Opcodes.swift @@ -203,6 +203,12 @@ enum Opcode { case switchBreak(SwitchBreak) case loadNewTarget(LoadNewTarget) case loopNestedContinue(LoopNestedContinue) + case loopNestedBreak(LoopNestedBreak) + case blockNestedBreak(BlockNestedBreak) + case ifNestedBreak(IfNestedBreak) + case tryNestedBreak(TryNestedBreak) + case switchNestedBreak(SwitchNestedBreak) + case withNestedBreak(WithNestedBreak) case print(Print) case explore(Explore) case probe(Probe) diff --git a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift index 63fa36fca..7b41d737c 100644 --- a/Sources/Fuzzilli/Lifting/FuzzILLifter.swift +++ b/Sources/Fuzzilli/Lifting/FuzzILLifter.swift @@ -756,6 +756,24 @@ public class FuzzILLifter: Lifter { case .loopNestedContinue(let op): w.emit("LoopNestedContinue \(op.depth)") + case .loopNestedBreak(let op): + w.emit("LoopNestedBreak \(op.depth)") + + case .blockNestedBreak(let op): + w.emit("BlockNestedBreak \(op.depth)") + + case .ifNestedBreak(let op): + w.emit("IfNestedBreak \(op.depth)") + + case .tryNestedBreak(let op): + w.emit("TryNestedBreak \(op.depth)") + + case .switchNestedBreak(let op): + w.emit("SwitchNestedBreak \(op.depth)") + + case .withNestedBreak(let op): + w.emit("WithNestedBreak \(op.depth)") + case .beginWasmModule: w.emit("BeginWasmModule") w.increaseIndentionLevel() diff --git a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift index c3c39571c..5a8908498 100644 --- a/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift +++ b/Sources/Fuzzilli/Lifting/JavaScriptLifter.swift @@ -102,6 +102,11 @@ public class JavaScriptLifter: Lifter { var w = JavaScriptWriter(analyzer: analyzer, version: version, stripComments: !options.contains(.includeComments), includeLineNumbers: options.contains(.includeLineNumbers)) var loopLabelStack = LabelStack(type: .loopblock) + var ifLabelStack = LabelStack(type: .ifblock) + var switchLabelStack = LabelStack(type: .switchblock) + var tryLabelStack = LabelStack(type: .tryblock) + var blockLabelStack = LabelStack(type: .codeBlock) + var withLabelStack = LabelStack(type: .withblock) var wasmCodeStarts: Int? = nil @@ -1037,12 +1042,14 @@ public class JavaScriptLifter: Lifter { case .beginWith: let OBJ = input(0) + withLabelStack.push(currentCodeLength: w.code.count) w.emit("with (\(OBJ)) {") w.enterNewBlock() case .endWith: w.leaveCurrentBlock() w.emit("}") + withLabelStack.pop() case .nop: break @@ -1109,6 +1116,7 @@ public class JavaScriptLifter: Lifter { if op.inverted { COND = UnaryExpression.new() + "!" + COND } + ifLabelStack.push(currentCodeLength: w.code.count) w.emit("if (\(COND)) {") w.enterNewBlock() @@ -1120,9 +1128,11 @@ public class JavaScriptLifter: Lifter { case .endIf: w.leaveCurrentBlock() w.emit("}") + ifLabelStack.pop() case .beginSwitch: let VALUE = input(0) + switchLabelStack.push(currentCodeLength: w.code.count) w.emit("switch (\(VALUE)) {") w.enterNewBlock() @@ -1144,6 +1154,7 @@ public class JavaScriptLifter: Lifter { case .endSwitch: w.leaveCurrentBlock() w.emit("}") + switchLabelStack.pop() case .beginWhileLoopHeader: // Must not inline across loop boundaries as that would change the program's semantics. @@ -1342,6 +1353,7 @@ public class JavaScriptLifter: Lifter { w.emit("continue;") case .beginTry: + tryLabelStack.push(currentCodeLength: w.code.count) w.emit("try {") w.enterNewBlock() @@ -1355,6 +1367,7 @@ public class JavaScriptLifter: Lifter { w.leaveCurrentBlock() w.emit("} finally {") w.enterNewBlock() + tryLabelStack.pop() case .endTryCatchFinally: w.leaveCurrentBlock() @@ -1383,6 +1396,7 @@ public class JavaScriptLifter: Lifter { w.emit("\(ESCAPE)`;") case .beginBlockStatement: + blockLabelStack.push(currentCodeLength: w.code.count) w.emit("{") w.enterNewBlock() @@ -1390,6 +1404,7 @@ public class JavaScriptLifter: Lifter { case .endBlockStatement: w.leaveCurrentBlock() w.emit("}") + blockLabelStack.pop() case .loadNewTarget: w.assign(Identifier.new("new.target"), to: instr.output) @@ -1403,6 +1418,36 @@ public class JavaScriptLifter: Lifter { loopLabelStack.translateContinueLabel(w: &writer, expDepth: op.depth) } + case .loopNestedBreak(let op): + w.withScriptWriter { writer in + loopLabelStack.translateBreakLabel(w: &writer, expDepth: op.depth) + } + + case .blockNestedBreak(let op): + w.withScriptWriter { writer in + blockLabelStack.translateBreakLabel(w: &writer, expDepth: op.depth) + } + + case .ifNestedBreak(let op): + w.withScriptWriter { writer in + ifLabelStack.translateBreakLabel(w: &writer, expDepth: op.depth) + } + + case .tryNestedBreak(let op): + w.withScriptWriter { writer in + tryLabelStack.translateBreakLabel(w: &writer, expDepth: op.depth) + } + + case .switchNestedBreak(let op): + w.withScriptWriter { writer in + switchLabelStack.translateBreakLabel(w: &writer, expDepth: op.depth) + } + + case .withNestedBreak(let op): + w.withScriptWriter { writer in + withLabelStack.translateBreakLabel(w: &writer, expDepth: op.depth) + } + case .createWasmGlobal(let op): let V = w.declare(instr.output) let LET = w.varKeyword diff --git a/Sources/Fuzzilli/Mutators/OperationMutator.swift b/Sources/Fuzzilli/Mutators/OperationMutator.swift index f241192cd..70a49f394 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -223,6 +223,18 @@ public class OperationMutator: BaseInstructionMutator { newOp = BeginIf(inverted: !op.inverted) case .loopNestedContinue(let op): newOp = LoopNestedContinue(Int.random(in: 0...10)) + case .loopNestedBreak(let op): + newOp = LoopNestedBreak(Int.random(in: 0...10)) + case .blockNestedBreak(let op): + newOp = BlockNestedBreak(Int.random(in: 0...10)) + case .ifNestedBreak(let op): + newOp = IfNestedBreak(Int.random(in: 0...10)) + case .tryNestedBreak(let op): + newOp = TryNestedBreak(Int.random(in: 0...10)) + case .switchNestedBreak(let op): + newOp = SwitchNestedBreak(Int.random(in: 0...10)) + case .withNestedBreak(let op): + newOp = WithNestedBreak(Int.random(in: 0...10)) case .createWasmGlobal(let op): // The type has to match for wasm, we cannot just switch types here as the rest of the wasm code will become invalid. // TODO: add nullref and funcref as types here. diff --git a/Sources/Fuzzilli/Protobuf/operations.pb.swift b/Sources/Fuzzilli/Protobuf/operations.pb.swift index 7552c7f3c..867acfad7 100644 --- a/Sources/Fuzzilli/Protobuf/operations.pb.swift +++ b/Sources/Fuzzilli/Protobuf/operations.pb.swift @@ -3046,6 +3046,75 @@ public struct Fuzzilli_Protobuf_LoopNestedContinue: Sendable { public init() {} } +public struct Fuzzilli_Protobuf_LoopNestedBreak: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct Fuzzilli_Protobuf_BlockNestedBreak: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} +public struct Fuzzilli_Protobuf_IfNestedBreak: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} +public struct Fuzzilli_Protobuf_TryNestedBreak: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} +public struct Fuzzilli_Protobuf_SwitchNestedBreak: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} +public struct Fuzzilli_Protobuf_WithNestedBreak: 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 depth: Int = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + + public struct Fuzzilli_Protobuf_BeginWasmModule: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -9574,6 +9643,120 @@ extension Fuzzilli_Protobuf_LoopNestedContinue: SwiftProtobuf.Message, SwiftProt } } +extension Fuzzilli_Protobuf_LoopNestedBreak: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".LoopNestedBreak" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_LoopNestedBreak, rhs: Fuzzilli_Protobuf_LoopNestedBreak) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_BlockNestedBreak: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".BlockNestedBreak" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_BlockNestedBreak, rhs: Fuzzilli_Protobuf_BlockNestedBreak) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_IfNestedBreak: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".IfNestedBreak" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_IfNestedBreak, rhs: Fuzzilli_Protobuf_IfNestedBreak) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_TryNestedBreak: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".TryNestedBreak" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_TryNestedBreak, rhs: Fuzzilli_Protobuf_TryNestedBreak) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_SwitchNestedBreak: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".SwitchNestedBreak" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_SwitchNestedBreak, rhs: Fuzzilli_Protobuf_SwitchNestedBreak) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Fuzzilli_Protobuf_WithNestedBreak: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".WithNestedBreak" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Fuzzilli_Protobuf_WithNestedBreak, rhs: Fuzzilli_Protobuf_WithNestedBreak) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Fuzzilli_Protobuf_BeginWasmModule: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".BeginWasmModule" public static let _protobuf_nameMap = SwiftProtobuf._NameMap() diff --git a/Sources/Fuzzilli/Protobuf/operations.proto b/Sources/Fuzzilli/Protobuf/operations.proto index 3afcd258c..1830cab84 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1223,6 +1223,24 @@ message WasmSelect { message LoopNestedContinue { } +message LoopNestedBreak { +} + +message BlockNestedBreak { +} + +message IfNestedBreak { +} + ++message TryNestedBreak { +} + +message SwitchNestedBreak { +} + +message WithNestedBreak { +} + message ConstSimd128 { repeated uint32 value = 1; } diff --git a/Sources/Fuzzilli/Protobuf/program.pb.swift b/Sources/Fuzzilli/Protobuf/program.pb.swift index b487bb643..39299b22c 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2265,6 +2265,56 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { set {operation = .loopNestedContinue(newValue)} } + public var loopNestedBreak: Fuzzilli_Protobuf_LoopNestedBreak { + get { + if case .loopNestedBreak(let v)? = operation {return v} + return Fuzzilli_Protobuf_LoopNestedBreak() + } + set {operation = .loopNestedBreak(newValue)} + } + + public var blockNestedBreak: Fuzzilli_Protobuf_BlockNestedBreak { + get { + if case .blockNestedBreak(let v)? = operation {return v} + return Fuzzilli_Protobuf_BlockNestedBreak() + } + set {operation = .blockNestedBreak(newValue)} + } + + public var ifNestedBreak: Fuzzilli_Protobuf_IfNestedBreak { + get { + if case .ifNestedBreak(let v)? = operation {return v} + return Fuzzilli_Protobuf_IfNestedBreak() + } + set {operation = .ifNestedBreak(newValue)} + } + + public var tryNestedBreak: Fuzzilli_Protobuf_TryNestedBreak { + get { + if case .tryNestedBreak(let v)? = operation {return v} + return Fuzzilli_Protobuf_TryNestedBreak() + } + set {operation = .tryNestedBreak(newValue)} + } + + public var switchNestedBreak: Fuzzilli_Protobuf_SwitchNestedBreak { + get { + if case .switchNestedBreak(let v)? = operation {return v} + return Fuzzilli_Protobuf_SwitchNestedBreak() + } + set {operation = .switchNestedBreak(newValue)} + } + + public var withNestedBreak: Fuzzilli_Protobuf_WithNestedBreak { + get { + if case .withNestedBreak(let v)? = operation {return v} + return Fuzzilli_Protobuf_WithNestedBreak() + } + set {operation = .withNestedBreak(newValue)} + } + + + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Operation: Equatable, Sendable { @@ -2545,6 +2595,12 @@ public struct Fuzzilli_Protobuf_Instruction: Sendable { case wasmUnreachable(Fuzzilli_Protobuf_WasmUnreachable) case wasmSelect(Fuzzilli_Protobuf_WasmSelect) case loopNestedContinue(Fuzzilli_Protobuf_LoopNestedContinue) + case loopNestedBreak(Fuzzilli_Protobuf_LoopNestedBreak) + case blockNestedBreak(Fuzzilli_Protobuf_BlockNestedBreak) + case ifNestedBreak(Fuzzilli_Protobuf_IfNestedBreak) + case tryNestedBreak(Fuzzilli_Protobuf_TryNestedBreak) + case switchNestedBreak(Fuzzilli_Protobuf_SwitchNestedBreak) + case withNestedBreak(Fuzzilli_Protobuf_WithNestedBreak) } public init() {} @@ -2871,6 +2927,12 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M 276: .same(proto: "wasmUnreachable"), 277: .same(proto: "wasmSelect"), 278: .same(proto: "loopNestedContinue"), + 279: .same(proto: "loopNestedBreak"), + 280: .same(proto: "blockNestedBreak"), + 281: .same(proto: "ifNestedBreak"), + 282: .same(proto: "tryNestedBreak"), + 283: .same(proto: "switchNestedBreak"), + 284: .same(proto: "withNestedBreak"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -6476,6 +6538,84 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M self.operation = .loopNestedContinue(v) } }() + case 279: try { + var v: Fuzzilli_Protobuf_LoopNestedBreak? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .loopNestedBreak(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .loopNestedBreak(v) + } + }() + case 280: try { + var v: Fuzzilli_Protobuf_BlockNestedBreak? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .blockNestedBreak(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .blockNestedBreak(v) + } + }() + case 281: try { + var v: Fuzzilli_Protobuf_IfNestedBreak? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .ifNestedBreak(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .ifNestedBreak(v) + } + }() + case 282: try { + var v: Fuzzilli_Protobuf_TryNestedBreak? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .tryNestedBreak(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .tryNestedBreak(v) + } + }() + case 283: try { + var v: Fuzzilli_Protobuf_SwitchNestedBreak? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .switchNestedBreak(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .switchNestedBreak(v) + } + }() + case 284: try { + var v: Fuzzilli_Protobuf_WithNestedBreak? + var hadOneofValue = false + if let current = self.operation { + hadOneofValue = true + if case .withNestedBreak(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.operation = .withNestedBreak(v) + } + }() default: break } } @@ -7596,6 +7736,30 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M }() case .loopNestedContinue?: try { guard case .loopNestedContinue(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 278) + }() + case .loopNestedBreak?: try { + guard case .loopNestedBreak(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 279) + }() + case .blockNestedBreak?: try { + guard case .blockNestedBreak(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 280) + }() + case .ifNestedBreak?: try { + guard case .ifNestedBreak(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 281) + }() + case .tryNestedBreak?: try { + guard case .tryNestedBreak(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 282) + }() + case .switchNestedBreak?: try { + guard case .switchNestedBreak(let v)? = self.operation else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 283) + }() + case .withNestedBreak?: try { + guard case .withNestedBreak(let v)? = self.operation else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 284) }() case nil: break diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index 8adcb7317..ae1b7ec63 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -302,6 +302,12 @@ message Instruction { WasmUnreachable wasmUnreachable = 276; WasmSelect wasmSelect = 277; LoopNestedContinue loopNestedContinue = 278; + LoopNestedBreak loopNestedBreak = 279; + BlockNestedBreak blockNestedBreak = 280; + IfNestedBreak ifNestedBreak = 281; + TryNestedBreak tryNestedBreak = 282; + SwitchNestedBreak switchNestedBreak = 283; + WithNestedBreak withNestedBreak = 284; } } diff --git a/Tests/FuzzilliTests/LifterTest.swift b/Tests/FuzzilliTests/LifterTest.swift index cffd10e06..5fdd6a953 100644 --- a/Tests/FuzzilliTests/LifterTest.swift +++ b/Tests/FuzzilliTests/LifterTest.swift @@ -3125,5 +3125,517 @@ class LifterTests: XCTestCase { """ XCTAssertEqual(actual, expected) } - + + // TestLoopNestedBreak0-6 is the nested break operation corresponding to different uses of the loop + func testLoopNestedBreakLifting0(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let d2 = 2 + let d3 = 3 + b.buildForLoop() { + b.buildForLoop() { + b.buildForLoop() { + b.loopNestedBreak(d2) + } + } + b.loopNestedBreak(d3) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + for (;;) { + for (;;) { + label2: + for (;;) { + break label2; + } + } + break label0; + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testLoopNestedBreakLifting1(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let a1 = b.loadInt(0) + + let d1 = 1 + let d3 = 3 + + b.buildWhileLoop({ b.compare(a1, with: b.loadInt(100), using: .lessThan) }) { + b.buildWhileLoop({ b.compare(a1, with: b.loadInt(100), using: .lessThan) }) { + b.buildWhileLoop({ b.compare(a1, with: b.loadInt(100), using: .lessThan) }) { + b.loopNestedBreak(d1) + } + } + b.loopNestedBreak(d3) + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + while (0 < 100) { + label1: + while (0 < 100) { + while (0 < 100) { + break label1; + } + } + break label0; + } + + """ + XCTAssertEqual(actual, expected) + + } + + func testLoopNestedBreakLifting2(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let a1 = b.loadInt(0) + + let d1 = 1 + let d3 = 3 + b.buildDoWhileLoop(do: { + b.buildDoWhileLoop(do: { + b.buildDoWhileLoop(do: { + }, while: { b.compare(a1, with: b.loadInt(100), using: .lessThan) }) + b.loopNestedBreak(d1) + }, while: { b.compare(a1, with: b.loadInt(100), using: .lessThan) }) + b.loopNestedBreak(d3) + }, while: { b.compare(a1, with: b.loadInt(100), using: .lessThan) }) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + do { + label1: + do { + do { + } while (0 < 100) + break label1; + } while (0 < 100) + break label0; + } while (0 < 100) + + """ + XCTAssertEqual(actual, expected) + } + + + func testLoopNestedBreakLifting3(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let a1 = b.loadInt(0) + + let d1 = 1 + let d3 = 3 + let v1 = b.createObject(with: ["a": a1]) + b.buildForInLoop(v1) { v2 in + b.buildForInLoop(v1) { v2 in + b.buildForInLoop(v1) { v2 in + b.loopNestedBreak(d1) + } + b.loopNestedBreak(d3) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v1 = { a: 0 }; + for (const v2 in v1) { + label1: + for (const v3 in v1) { + for (const v4 in v1) { + break label1; + } + break label1; + } + } + + """ + XCTAssertEqual(actual, expected) + + } + + + func testLoopNestedBreakLifting4(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let n1 = b.loadFloat(Double.nan) + let v1 = b.createArray(with: [n1, n1, n1]) + + let d2 = 2 + b.buildForOfLoop(v1) { v2 in + b.buildForOfLoop(v1) { v2 in + b.buildForOfLoop(v1) { v2 in + } + b.loopNestedBreak(d2) + } + } + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v1 = [NaN,NaN,NaN]; + label0: + for (const v2 of v1) { + for (const v3 of v1) { + for (const v4 of v1) { + } + break label0; + } + } + + """ + XCTAssertEqual(actual, expected) + + } + + func testLoopNestedBreakLifting5(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let a1 = b.createArray(with: [b.loadInt(10), b.loadInt(11), b.loadInt(12), b.loadInt(13), b.loadInt(14)]) + let a2 = b.createArray(with: [b.loadInt(20), b.loadInt(21), b.loadInt(22), b.loadInt(23)]) + let a3 = b.createArray(with: [b.loadInt(30), b.loadInt(31), b.loadInt(32)]) + let a4 = b.createArray(with: [a1, a2, a3]) + + let d2 = 2 + + b.buildForOfLoop(a4, selecting: [0,2], hasRestElement: true) { args in + + b.buildForOfLoop(a4, selecting: [0,2], hasRestElement: true) { args in + b.buildForOfLoop(a4, selecting: [0,2], hasRestElement: true) { args in + } + b.loopNestedBreak(d2) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + const v15 = [[10,11,12,13,14],[20,21,22,23],[30,31,32]]; + label0: + for (let [v16,,...v17] of v15) { + for (let [v18,,...v19] of v15) { + for (let [v20,,...v21] of v15) { + } + break label0; + } + } + + """ + XCTAssertEqual(actual, expected) + + } + + func testLoopNestedBreakLifting6(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let d1 = 1 + let d2 = 2 + + b.buildRepeatLoop(n: 10) { d1 + b.buildRepeatLoop(n: 10) { d1 + b.buildRepeatLoop(n: 10) { d1 + } + b.loopNestedBreak(d2) + } + } + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + for (let i = 0; i < 10; i++) { + for (let i = 0; i < 10; i++) { + for (let i = 0; i < 10; i++) { + } + break label0; + } + } + + """ + XCTAssertEqual(actual, expected) + } + + // testLoopNestedBreak7 is a comprehensive test of the loop + // 1. breaking and continuing to the same label + // 2. breaking/continuing to the same label multiple times from different depths + // 3. breaking out of a loop at depth 1 + // 4. breaking out of a loop at depth 2 + func testLoopNestedBreakLifting7(){ + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildRepeatLoop(n: 10) { + b.buildRepeatLoop(n: 10) { + b.buildRepeatLoop(n: 10) { + b.loopNestedBreak(0) + } + b.loopNestedBreak(0) + b.loopNestedBreak(1) + } + } + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + for (let i = 0; i < 10; i++) { + label1: + for (let i = 0; i < 10; i++) { + for (let i = 0; i < 10; i++) { + break label0; + } + break label0; + break label1; + } + } + + """ + XCTAssertEqual(actual, expected) + } + + func testBlockNestedBreakLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.blockStatement{ + b.blockStatement { + b.blockStatement { + b.blockNestedBreak(0) + } + b.blockNestedBreak(0) + b.blockNestedBreak(1) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + { + label1: + { + { + break label0; + } + break label0; + break label1; + } + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testTryNestedBreakLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + b.buildTryCatchFinally(tryBody: { + b.buildTryCatchFinally(tryBody: { + b.buildTryCatchFinally(tryBody: { + b.tryNestedBreak(0) + }, catchBody: { _ in}) + b.tryNestedBreak(0) + b.tryNestedBreak(1) + }, catchBody: { _ in + b.tryNestedBreak(1) + }){ + } + }, catchBody: { _ in}) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + + let expected = """ + label0: + try { + label1: + try { + try { + break label0; + } catch(e0) { + } + break label0; + break label1; + } catch(e1) { + break label1; + } finally { + } + } catch(e2) { + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testIfNestedBreakLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let cmp = b.loadBool(false) + + b.buildIfElse(cmp, ifBody: { + b.buildIfElse(cmp, ifBody: { + b.ifNestedBreak(0) + }, elseBody: { + b.buildIfElse(cmp, ifBody: { + b.ifNestedBreak(0) + }, elseBody: { + b.ifNestedBreak(1) + }) + }) + }, elseBody: { + b.ifNestedBreak(2) + }) + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + let expected = """ + label0: + if (false) { + label1: + if (false) { + break label0; + } else { + if (false) { + break label0; + } else { + break label1; + } + } + } else { + break label0; + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testSwitchNestedBreakLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let v0 = b.loadInt(42) + let v1 = b.createObject(with: ["foo": v0]) + let v2 = b.getProperty("foo", of: v1) + let v3 = b.loadInt(1337) + let v4 = b.loadString("42") + + b.buildSwitch(on: v2) { swtch in + swtch.addCase(v3, fallsThrough: false) { + } + swtch.addCase(v4, fallsThrough: false){ + let v0 = b.loadInt(42) + let v1 = b.createObject(with: ["foo": v0]) + let v2 = b.getProperty("foo", of: v1) + let v3 = b.loadInt(1337) + let v4 = b.loadString("42") + let v5 = b.loadFloat(13.37) + b.buildSwitch(on: v2) { swtch in + swtch.addCase(v3, fallsThrough: false) { + } + swtch.addCase(v4, fallsThrough: false){ + b.switchNestedBreak(1) + } + swtch.addDefaultCase(fallsThrough: true){ + b.switchNestedBreak(2) + } + } + } + swtch.addDefaultCase(fallsThrough: true){ + b.switchNestedBreak(0) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + let expected = """ + label0: + switch (({ foo: 42 }).foo) { + case 1337: + break; + case "42": + label1: + switch (({ foo: 42 }).foo) { + case 1337: + break; + case "42": + break label1; + break; + default: + break label0; + } + break; + default: + break label0; + } + + """ + + XCTAssertEqual(actual, expected) + } + + func testWithNestedBreakLifting() { + let fuzzer = makeMockFuzzer() + let b = fuzzer.makeBuilder() + + let obj = b.loadString("HelloWorld") + b.buildWith(obj) { + b.buildWith(obj) { + b.buildWith(obj) { + b.withNestedBreak(2) + } + b.withNestedBreak(0) + b.withNestedBreak(1) + } + } + + let program = b.finalize() + let actual = fuzzer.lifter.lift(program) + let expected = """ + label0: + with ("HelloWorld") { + label1: + with ("HelloWorld") { + label2: + with ("HelloWorld") { + break label2; + } + break label0; + break label1; + } + } + + """ + XCTAssertEqual(actual, expected) + } } \ No newline at end of file