diff --git a/Sources/Fuzzilli/Base/ProgramBuilder.swift b/Sources/Fuzzilli/Base/ProgramBuilder.swift index 0df465c17..e3c38381c 100644 --- a/Sources/Fuzzilli/Base/ProgramBuilder.swift +++ b/Sources/Fuzzilli/Base/ProgramBuilder.swift @@ -2822,6 +2822,34 @@ public class ProgramBuilder { emit(Print(), withInputs: [value]) } + public func loopNestedContinue(_ depth: Int){ + 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 54dc9efc8..6e5f61a55 100644 --- a/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift +++ b/Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift @@ -169,6 +169,13 @@ public let codeGeneratorWeights = [ "TryCatchGenerator": 5, "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 fdb9bc330..8acb19a10 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 +2349,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..70a49f394 100644 --- a/Sources/Fuzzilli/Mutators/OperationMutator.swift +++ b/Sources/Fuzzilli/Mutators/OperationMutator.swift @@ -221,6 +221,20 @@ 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 .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 0efd2ada8..867acfad7 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,87 @@ 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_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 @@ -9502,6 +9585,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 +9624,139 @@ 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_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 e9ae34bf2..1830cab84 100644 --- a/Sources/Fuzzilli/Protobuf/operations.proto +++ b/Sources/Fuzzilli/Protobuf/operations.proto @@ -1220,6 +1220,27 @@ message WasmSelect { WasmILType type = 1; } +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 eeaa73cf4..39299b22c 100644 --- a/Sources/Fuzzilli/Protobuf/program.pb.swift +++ b/Sources/Fuzzilli/Protobuf/program.pb.swift @@ -2257,6 +2257,64 @@ 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 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 { @@ -2536,7 +2594,13 @@ 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) + 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() {} @@ -2862,6 +2926,13 @@ extension Fuzzilli_Protobuf_Instruction: SwiftProtobuf.Message, SwiftProtobuf._M 275: .same(proto: "wasmSimdLoad"), 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 { @@ -6454,6 +6525,97 @@ 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) + } + }() + 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 } } @@ -7572,6 +7734,34 @@ 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: 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 } try unknownFields.traverse(visitor: &visitor) diff --git a/Sources/Fuzzilli/Protobuf/program.proto b/Sources/Fuzzilli/Protobuf/program.proto index c3bd42a18..ae1b7ec63 100644 --- a/Sources/Fuzzilli/Protobuf/program.proto +++ b/Sources/Fuzzilli/Protobuf/program.proto @@ -301,6 +301,13 @@ message Instruction { WasmSimdLoad wasmSimdLoad = 275; 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/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..5fdd6a953 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,547 @@ 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) + } + + // 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