Skip to content

Fuzzing: Update FuzzTranslator to instantiate modules explicitly #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 23, 2024
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
4 changes: 4 additions & 0 deletions FuzzTesting/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ let package = Package(
],
targets: [
.target(name: "FuzzTranslator", dependencies: [
"WasmKitFuzzing",
.product(name: "WasmKit", package: "WasmKit")
]),
.target(name: "FuzzExecute", dependencies: [
Expand All @@ -42,5 +43,8 @@ let package = Package(
"WasmCAPI",
]),
.target(name: "WasmCAPI"),
.target(name: "WasmKitFuzzing", dependencies: [
.product(name: "WasmKit", package: "WasmKit"),
])
]
)
4 changes: 2 additions & 2 deletions FuzzTesting/Sources/FuzzTranslator/FuzzTranslator.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import WasmKit
import WasmKitFuzzing

@_cdecl("LLVMFuzzerTestOneInput")
public func FuzzCheck(_ start: UnsafePointer<UInt8>, _ count: Int) -> CInt {
let bytes = Array(UnsafeBufferPointer(start: start, count: count))
do {
var module = try WasmKit.parseWasm(bytes: bytes)
try module.materializeAll()
try fuzzInstantiation(bytes: bytes)
} catch {
// Ignore errors
}
Expand Down
41 changes: 41 additions & 0 deletions FuzzTesting/Sources/WasmKitFuzzing/WasmKitFuzzing.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// This module defines utilities for fuzzing WasmKit.

import WasmKit

/// Check if a Wasm module can be instantiated without crashing.
///
/// - Parameter bytes: The bytes of the Wasm module.
public func fuzzInstantiation(bytes: [UInt8]) throws {
let module = try WasmKit.parseWasm(bytes: bytes)
let engine = Engine(configuration: EngineConfiguration(compilationMode: .eager))
let store = Store(engine: engine)

// Prepare dummy imports
var imports = Imports()
for importEntry in module.imports {
let value: ExternalValueConvertible
switch importEntry.descriptor {
case .function(let typeIndex):
guard typeIndex < module.types.count else {
// Skip if import type index is out of bounds
return
}
let type = module.types[Int(typeIndex)]
value = Function(store: store, type: type) { _, _ in
// Provide "start function" with empty results
if type.results.isEmpty { return [] }
fatalError("Unexpected function call")
}
case .global(let globalType):
value = try Global(store: store, type: globalType, value: .i32(0))
case .memory(let memoryType):
value = try Memory(store: store, type: memoryType)
case .table(let tableType):
value = try Table(store: store, type: tableType)
}
imports.define(module: importEntry.module, name: importEntry.name, value.externalValue)
}

// Instantiate the module
_ = try module.instantiate(store: store, imports: imports)
}
7 changes: 6 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ let package = Package(
exclude: ["CMakeLists.txt"]
),
.target(name: "_CWasmKit"),
.target(
name: "WasmKitFuzzing",
dependencies: ["WasmKit"],
path: "FuzzTesting/Sources/WasmKitFuzzing"
),
.testTarget(
name: "WasmKitTests",
dependencies: ["WasmKit", "WAT"],
dependencies: ["WasmKit", "WAT", "WasmKitFuzzing"],
exclude: ["ExtraSuite"]
),

Expand Down
13 changes: 2 additions & 11 deletions Sources/WasmKit/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,8 @@ public struct Module {
}

/// Materialize lazily-computed elements in this module
public mutating func materializeAll() throws {
let allocator = ISeqAllocator()
let funcTypeInterner = Interner<FunctionType>()
for function in functions {
_ = try function.compile(module: self, funcTypeInterner: funcTypeInterner, allocator: allocator)
}
}
@available(*, deprecated, message: "Module materialization is no longer supported. Instantiate the module explicitly instead.")
public mutating func materializeAll() throws {}
}

extension Module {
Expand Down Expand Up @@ -275,8 +270,4 @@ typealias LabelIndex = UInt32
struct GuestFunction {
let type: FunctionType
let code: Code

func compile(module: Module, funcTypeInterner: Interner<FunctionType>, allocator: ISeqAllocator) throws -> InstructionSequence {
throw TranslationError("Compile without instantiation is no longer supported")
}
}
29 changes: 4 additions & 25 deletions Tests/WasmKitTests/FuzzTranslatorRegressionTests.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import WasmKit
import WasmKitFuzzing
import XCTest

final class FuzzTranslatorRegressionTests: XCTestCase {
func testRunAll() async throws {
func testRunAll() throws {
let sourceRoot = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent()
let failCasesDir =
Expand All @@ -12,33 +13,11 @@ final class FuzzTranslatorRegressionTests: XCTestCase {
for file in try FileManager.default.contentsOfDirectory(atPath: failCasesDir.path) {
let path = failCasesDir.appendingPathComponent(file).path
print("Fuzz regression test: \(path.dropFirst(sourceRoot.path.count + 1))")

let data = try Data(contentsOf: URL(fileURLWithPath: path))
do {
let module = try WasmKit.parseWasm(bytes: Array(data))
let engine = Engine(configuration: EngineConfiguration(compilationMode: .eager))
let store = Store(engine: engine)
var imports = Imports()
for importEntry in module.imports {
let value: ExternalValueConvertible
switch importEntry.descriptor {
case .function(let typeIndex):
let type = module.types[Int(typeIndex)]
value = Function(store: store, type: type) { _, _ in
fatalError("unreachable")
}
case .global(let globalType):
value = try Global(store: store, type: globalType, value: .i32(0))
case .memory(let memoryType):
value = try Memory(store: store, type: memoryType)
case .table(let tableType):
value = try Table(store: store, type: tableType)
}
imports.define(module: importEntry.module, name: importEntry.name, value.externalValue)
}
_ = try module.instantiate(store: store, imports: imports)
try WasmKitFuzzing.fuzzInstantiation(bytes: Array(data))
} catch {
// Explicit errors are ok
// Skip exceptions without crash
}
}
}
Expand Down