diff --git a/FuzzTesting/FailCases/FuzzDifferential/diff-259df1650a6738711fc751c0ff56f40b0327b49e.wasm b/FuzzTesting/FailCases/FuzzDifferential/diff-259df1650a6738711fc751c0ff56f40b0327b49e.wasm new file mode 100644 index 00000000..d460d8dc Binary files /dev/null and b/FuzzTesting/FailCases/FuzzDifferential/diff-259df1650a6738711fc751c0ff56f40b0327b49e.wasm differ diff --git a/FuzzTesting/FailCases/FuzzDifferential/diff-3cefb827c90b7927cc0c576d83caf9ff5bb9c9f7.wasm b/FuzzTesting/FailCases/FuzzDifferential/diff-3cefb827c90b7927cc0c576d83caf9ff5bb9c9f7.wasm new file mode 100644 index 00000000..10650b65 Binary files /dev/null and b/FuzzTesting/FailCases/FuzzDifferential/diff-3cefb827c90b7927cc0c576d83caf9ff5bb9c9f7.wasm differ diff --git a/FuzzTesting/Sources/FuzzDifferential/FuzzDifferential.swift b/FuzzTesting/Sources/FuzzDifferential/FuzzDifferential.swift index 172f9ac8..501f0e53 100644 --- a/FuzzTesting/Sources/FuzzDifferential/FuzzDifferential.swift +++ b/FuzzTesting/Sources/FuzzDifferential/FuzzDifferential.swift @@ -5,9 +5,16 @@ import SystemPackage import Foundation protocol Engine { + var name: String { get } func run(moduleBytes: [UInt8]) throws -> ExecResult } +extension Engine { + var name: String { + return String(describing: type(of: self)) + } +} + struct ExecResult { let values: [Value]? let trap: String? @@ -17,30 +24,32 @@ struct ExecResult { return trap != nil } - static func check(_ lhs: ExecResult, _ rhs: ExecResult) -> Bool { + static func check(_ lhs: (result: ExecResult, name: String), _ rhs: (result: ExecResult, name: String)) -> Bool { + let (lhsName, rhsName) = (lhs.name, rhs.name) + let (lhs, rhs) = (lhs.result, rhs.result) guard lhs.hasTrap == rhs.hasTrap else { - print("Traps do not match: \(lhs.trap ?? "nil") vs \(rhs.trap ?? "nil")") + print("Traps do not match: \(lhsName):\(lhs.trap ?? "nil") vs \(rhsName):\(rhs.trap ?? "nil")") return false } guard lhs.memory == rhs.memory else { guard lhs.memory?.count == rhs.memory?.count else { - print("Memory sizes do not match: \(lhs.memory?.count ?? 0) vs \(rhs.memory?.count ?? 0)") + print("Memory sizes do not match: \(lhsName):\(lhs.memory?.count ?? 0) vs \(rhsName):\(rhs.memory?.count ?? 0)") return false } for (i, (lhsByte, rhsByte)) in zip(lhs.memory ?? [], rhs.memory ?? []).enumerated() { if lhsByte != rhsByte { - print("Memory byte \(i) does not match: \(lhsByte) vs \(rhsByte)") + print("Memory byte \(i) does not match: \(lhsName):\(lhsByte) vs \(rhsName):\(rhsByte)") } } return false } guard lhs.values?.count == rhs.values?.count else { - print("Value counts do not match: \(lhs.values?.count ?? 0) vs \(rhs.values?.count ?? 0)") + print("Value counts do not match: \(lhsName):\(lhs.values?.count ?? 0) vs \(rhsName):\(rhs.values?.count ?? 0)") return false } for (i, (lhsValue, rhsValue)) in zip(lhs.values ?? [], rhs.values ?? []).enumerated() { if !Value.bitwiseEqual(lhsValue, rhsValue) { - print("Value \(i) does not match: \(lhsValue) vs \(rhsValue)") + print("Value \(i) does not match: \(lhsName):\(lhsValue) vs \(rhsName):\(rhsValue)") return false } } @@ -90,6 +99,7 @@ extension wasm_name_t { } struct WasmKitEngine: Engine { + var name: String { return "wasmkit" } func run(moduleBytes: [UInt8]) throws -> ExecResult { let module = try WasmKit.parseWasm(bytes: moduleBytes) let engine = WasmKit.Engine() @@ -127,6 +137,7 @@ struct WasmKitEngine: Engine { } struct ReferenceEngine: Engine { + var name: String { return "reference" } func run(moduleBytes: [UInt8]) throws -> ExecResult { return try moduleBytes.withUnsafeBytes { (module: UnsafeRawBufferPointer) -> ExecResult in try run(module: module) @@ -275,7 +286,7 @@ struct ReferenceEngine: Engine { } else { moduleBytes = try Array(Data(contentsOf: URL(fileURLWithPath: moduleFile))) } - let results = try engines.map { try $0.run(moduleBytes: moduleBytes) } + let results = try engines.map { try ($0.run(moduleBytes: moduleBytes), $0.name) } guard results.count > 1 else { throw ExecError("Expected at least two engines") } diff --git a/FuzzTesting/differential.py b/FuzzTesting/differential.py index 8862c187..ebc0ceed 100755 --- a/FuzzTesting/differential.py +++ b/FuzzTesting/differential.py @@ -42,6 +42,7 @@ async def run_single(lane, i, program): "-o", wasm_file, "--ensure-termination", "--bulk-memory-enabled=true", + "--canonicalize-nans=true", "--saturating-float-to-int-enabled=true", "--sign-extension-ops-enabled=true", "--min-funcs=1", diff --git a/Sources/WasmKit/Translator.swift b/Sources/WasmKit/Translator.swift index e09cf547..13c0f5ad 100644 --- a/Sources/WasmKit/Translator.swift +++ b/Sources/WasmKit/Translator.swift @@ -959,6 +959,7 @@ struct InstructionTranslator: InstructionVisitor { guard try checkBeforePop(typeHint: type) else { return nil } + iseqBuilder.resetLastEmission() return try valueStack.pop(type) } @@ -976,6 +977,7 @@ struct InstructionTranslator: InstructionVisitor { guard try checkBeforePop(typeHint: nil) else { return (.unknown, nil) } + iseqBuilder.resetLastEmission() return try valueStack.pop() } @@ -1125,6 +1127,7 @@ struct InstructionTranslator: InstructionVisitor { mutating func visitBlock(blockType: WasmParser.BlockType) throws -> Output { let blockType = try module.resolveBlockType(blockType) let endLabel = iseqBuilder.allocLabel() + self.preserveLocalsOnStack(depth: self.valueStack.height) let stackHeight = try popPushValues(blockType.parameters) controlStack.pushFrame(ControlStack.ControlFrame(blockType: blockType, stackHeight: stackHeight, continuation: endLabel, kind: .block)) } diff --git a/Tests/WasmKitTests/ExtraSuite/br_if.wast b/Tests/WasmKitTests/ExtraSuite/br_if.wast index 54e218fa..6be76dcf 100644 --- a/Tests/WasmKitTests/ExtraSuite/br_if.wast +++ b/Tests/WasmKitTests/ExtraSuite/br_if.wast @@ -12,3 +12,21 @@ (assert_return (invoke "brif_not_taken" (i32.const 3)) (i32.const 6)) +(module + (func (export "check") + (local i64 i32 f32) + i64.const 4 + ;; use non-const nor local instruction to force + ;; leaving local.set at runtime + i64.clz + + i32.const 0 + i32.eqz + ;; popping the i32.eqz should invalidate the relinking state + br_if 0 + local.set 0 + unreachable) +) + + +(invoke "check") diff --git a/Tests/WasmKitTests/ExtraSuite/local_cow.wast b/Tests/WasmKitTests/ExtraSuite/local_cow.wast index 68d6f02b..1826bd60 100644 --- a/Tests/WasmKitTests/ExtraSuite/local_cow.wast +++ b/Tests/WasmKitTests/ExtraSuite/local_cow.wast @@ -49,3 +49,21 @@ ) (assert_return (invoke "invalidate-relink" (i32.const 1) (i32.const 2)) (i32.const 2)) + +(module + (global (mut i32) (i32.const 4)) + (func (export "check") (result i32) + (local i32) + global.get 0 + drop + local.get 0 + block + i32.const 1 + br_if 0 + i32.const 0 + local.set 0 + end + ) +) + +(assert_return (invoke "check") (i32.const 0))