Skip to content

Commit eecaf99

Browse files
Validation: Ban function references to undeclared functions
1 parent f71063a commit eecaf99

File tree

6 files changed

+31
-9
lines changed

6 files changed

+31
-9
lines changed

Sources/WasmKit/Execution/ConstEvaluation.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ protocol ConstEvaluationContextProtocol {
88
struct ConstEvaluationContext: ConstEvaluationContextProtocol {
99
let functions: ImmutableArray<InternalFunction>
1010
var globals: [Value]
11+
let onFunctionReferenced: ((InternalFunction) -> Void)?
1112

12-
init(functions: ImmutableArray<InternalFunction>, globals: [Value]) {
13+
init(
14+
functions: ImmutableArray<InternalFunction>,
15+
globals: [Value],
16+
onFunctionReferenced: ((InternalFunction) -> Void)? = nil
17+
) {
1318
self.functions = functions
1419
self.globals = globals
20+
self.onFunctionReferenced = onFunctionReferenced
1521
}
1622

1723
init(instance: InternalInstance, moduleImports: ModuleImports) {
@@ -23,7 +29,9 @@ struct ConstEvaluationContext: ConstEvaluationContextProtocol {
2329
}
2430

2531
func functionRef(_ index: FunctionIndex) throws -> Reference {
26-
return try .function(from: self.functions[validating: Int(index)])
32+
let function = try self.functions[validating: Int(index)]
33+
self.onFunctionReferenced?(function)
34+
return .function(from: function)
2735
}
2836
func globalValue(_ index: GlobalIndex) throws -> Value {
2937
guard index < globals.count else {

Sources/WasmKit/Execution/Instances.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ struct InstanceEntity /* : ~Copyable */ {
7676
var elementSegments: ImmutableArray<InternalElementSegment>
7777
var dataSegments: ImmutableArray<InternalDataSegment>
7878
var exports: [String: InternalExternalValue]
79+
var functionRefs: Set<InternalFunction>
7980
var features: WasmFeatureSet
8081
var hasDataCount: Bool
8182

@@ -89,6 +90,7 @@ struct InstanceEntity /* : ~Copyable */ {
8990
elementSegments: ImmutableArray(),
9091
dataSegments: ImmutableArray(),
9192
exports: [:],
93+
functionRefs: [],
9294
features: [],
9395
hasDataCount: false
9496
)

Sources/WasmKit/Execution/StoreAllocator.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,16 @@ extension StoreAllocator {
360360
allocateHandle: { m, _ in try allocate(memoryType: m, resourceLimiter: resourceLimiter) }
361361
)
362362

363+
var functionRefs: Set<InternalFunction> = []
363364
// Step 5.
364365
let constEvalContext = ConstEvaluationContext(
365366
functions: functions,
366-
globals: importedGlobals.map(\.value)
367+
globals: importedGlobals.map(\.value),
368+
onFunctionReferenced: { function in
369+
functionRefs.insert(function)
370+
}
367371
)
372+
368373
let globals = try allocateEntities(
369374
imports: importedGlobals,
370375
internals: module.globals,
@@ -379,13 +384,13 @@ extension StoreAllocator {
379384
// Step 6.
380385
let elements = try ImmutableArray<InternalElementSegment>(allocator: arrayAllocator, count: module.elements.count) { buffer in
381386
for (index, element) in module.elements.enumerated() {
382-
let references: [Reference]
387+
// TODO: Avoid evaluating element expr twice in `Module.instantiate` and here.
388+
var references = try element.evaluateInits(context: constEvalContext)
383389
switch element.mode {
384390
case .active, .declarative:
385391
// active & declarative segments are unavailable at runtime
386392
references = []
387-
case .passive:
388-
references = try element.evaluateInits(context: constEvalContext)
393+
case .passive: break
389394
}
390395
let handle = allocate(elementType: element.type, references: references)
391396
buffer.initializeElement(at: index, to: handle)
@@ -449,6 +454,7 @@ extension StoreAllocator {
449454
elementSegments: elements,
450455
dataSegments: dataSegments,
451456
exports: exports,
457+
functionRefs: functionRefs,
452458
features: module.features,
453459
hasDataCount: module.hasDataCount
454460
)

Sources/WasmKit/Translator.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,10 @@ extension InternalInstance: TranslatorContext {
118118
_ = try self.dataSegments[validating: Int(index)]
119119
}
120120
func validateFunctionIndex(_ index: FunctionIndex) throws {
121-
_ = try self.functions[validating: Int(index)]
121+
let function = try self.functions[validating: Int(index)]
122+
guard self.functionRefs.contains(function) else {
123+
throw ValidationError("Function index \(index) is not declared but referenced as a function reference")
124+
}
122125
}
123126
}
124127

@@ -1752,7 +1755,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
17521755
emit(.refIsNull(Instruction.RefIsNullOperand(value: LVReg(ensureOnVReg(value)), result: LVReg(result))))
17531756
}
17541757
mutating func visitRefFunc(functionIndex: UInt32) throws -> Output {
1755-
try self.module.validateFunctionIndex(functionIndex)
1758+
try validator.validateRefFunc(functionIndex: functionIndex)
17561759
pushEmit(.ref(.funcRef), { .refFunc(Instruction.RefFuncOperand(index: functionIndex, result: LVReg($0))) })
17571760
}
17581761

Sources/WasmKit/Validator.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ struct InstructionValidator<Context: TranslatorContext> {
4242
throw ValidationError("Table element type mismatch in table.init: \(tableType.elementType) != \(elementType)")
4343
}
4444
}
45+
46+
func validateRefFunc(functionIndex: UInt32) throws {
47+
try context.validateFunctionIndex(functionIndex)
48+
}
4549
}
4650

4751
struct ModuleValidator {

Tests/WasmKitTests/SpectestTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ final class SpectestTests: XCTestCase {
2222
path: Self.testPaths,
2323
include: [],
2424
exclude: [
25-
"ref_func.wast",
2625
"select.wast",
2726
"start.wast",
2827
"table-sub.wast",

0 commit comments

Comments
 (0)