Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
25 changes: 18 additions & 7 deletions FuzzTesting/Sources/FuzzDifferential/FuzzDifferential.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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")
}
Expand Down
1 change: 1 addition & 0 deletions FuzzTesting/differential.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions Sources/WasmKit/Translator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
guard try checkBeforePop(typeHint: type) else {
return nil
}
iseqBuilder.resetLastEmission()
return try valueStack.pop(type)
}

Expand All @@ -976,6 +977,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
guard try checkBeforePop(typeHint: nil) else {
return (.unknown, nil)
}
iseqBuilder.resetLastEmission()
return try valueStack.pop()
}

Expand Down Expand Up @@ -1125,6 +1127,7 @@ struct InstructionTranslator<Context: TranslatorContext>: 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))
}
Expand Down
18 changes: 18 additions & 0 deletions Tests/WasmKitTests/ExtraSuite/br_if.wast
Original file line number Diff line number Diff line change
Expand Up @@ -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")
18 changes: 18 additions & 0 deletions Tests/WasmKitTests/ExtraSuite/local_cow.wast
Original file line number Diff line number Diff line change
Expand Up @@ -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))