Skip to content

Commit 7e46572

Browse files
Validation: Fix unreachable if block with else
1 parent c91dfb4 commit 7e46572

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

Sources/WasmKit/Translator.swift

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
298298
enum Kind {
299299
case block(root: Bool)
300300
case loop
301-
case `if`(elseLabel: LabelRef, endLabel: LabelRef)
301+
case `if`(elseLabel: LabelRef, endLabel: LabelRef, isElse: Bool)
302302

303303
static var block: Kind { .block(root: false) }
304304
}
@@ -1113,7 +1113,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11131113
controlStack.pushFrame(
11141114
ControlStack.ControlFrame(
11151115
blockType: blockType, stackHeight: stackHeight, continuation: endLabel,
1116-
kind: .if(elseLabel: elseLabel, endLabel: endLabel)
1116+
kind: .if(elseLabel: elseLabel, endLabel: endLabel, isElse: false)
11171117
)
11181118
)
11191119
guard let condition = condition else { return }
@@ -1130,8 +1130,8 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11301130
}
11311131

11321132
mutating func visitElse() throws -> Output {
1133-
let frame = try controlStack.currentFrame()
1134-
guard case let .if(elseLabel, endLabel) = frame.kind else {
1133+
var frame = try controlStack.currentFrame()
1134+
guard case let .if(elseLabel, endLabel, _) = frame.kind else {
11351135
throw TranslationError("Expected `if` control frame on top of the stack for `else` but got \(frame)")
11361136
}
11371137
preserveOnStack(depth: valueStack.height - frame.stackHeight)
@@ -1141,7 +1141,18 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11411141
let offset = endPC.offsetFromHead - selfPC.offsetFromHead
11421142
return Int32(offset)
11431143
}
1144-
try valueStack.truncate(height: frame.stackHeight)
1144+
for result in frame.blockType.results.reversed() {
1145+
guard try checkBeforePop(typeHint: result, controlFrame: frame) else { continue }
1146+
_ = try valueStack.pop(result)
1147+
}
1148+
guard valueStack.height == frame.stackHeight else {
1149+
throw ValidationError("values remaining on stack at end of block")
1150+
}
1151+
_ = controlStack.popFrame()
1152+
frame.kind = .if(elseLabel: elseLabel, endLabel: endLabel, isElse: true)
1153+
frame.reachable = true
1154+
controlStack.pushFrame(frame)
1155+
11451156
// Re-push parameters
11461157
for parameter in frame.blockType.parameters {
11471158
_ = valueStack.push(parameter)
@@ -1179,6 +1190,14 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11791190
return
11801191
}
11811192

1193+
if case .if(_, _, isElse: false) = poppedFrame.kind {
1194+
// `if` inst without `else` must have the same parameter and result types
1195+
let blockType = poppedFrame.blockType
1196+
guard blockType.parameters == blockType.results else {
1197+
throw TranslationError("Expected the same parameter and result types for `if` block but got \(blockType)")
1198+
}
1199+
}
1200+
11821201
// NOTE: `valueStack.height - poppedFrame.stackHeight` is usually the same as `poppedFrame.copyCount`
11831202
// but it's not always the case when this block is already unreachable.
11841203
preserveOnStack(depth: Int(valueStack.height - poppedFrame.stackHeight))

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-
"if.wast",
2625
"imports.wast",
2726
"labels.wast",
2827
"load.wast",

0 commit comments

Comments
 (0)