diff --git a/harness/src/runner.ts b/harness/src/runner.ts index e23af40..ce7edfd 100644 --- a/harness/src/runner.ts +++ b/harness/src/runner.ts @@ -342,6 +342,65 @@ const TRAP_MESSAGE_EQUIVALENTS: Array< "unreachable", ["Unreachable code should not be executed"], ], + // Wasmtime's supplementary corpus uses the bare canonical core-trap name + // (crates/environ/src/trap_encoding.rs:138), unlike the official corpus's + // longer form above. The runtime still exposes raw engine text through + // mapCoreException, so this is the same core `unreachable` operation. + [ + "wasm `unreachable` instruction executed", + [ + "guest trapped: unreachable", + "guest trapped: unreachable executed", + "guest trapped: Unreachable code should not be executed", + ], + ], + // definitions.py:2344-2355 gives inc-at-2^16 and dec-below-zero the same + // trap operation. Pinned Wasmtime deliberately names that shared category + // BackpressureOverflow (crates/environ/src/trap_encoding.rs:254-256). + ["backpressure counter overflow", ["backpressure counter underflow"]], + // definitions.py:2445-2452 rejects exactly resolve_delivered(); these are + // the pinned Wasmtime category and runtime call-site spellings for it. + [ + "`subtask.cancel` called after terminal status delivered", + ["subtask.cancel on a subtask whose resolution was already delivered"], + ], + // definitions.py:2512,2566,2618 has one condition for a synchronous + // read/write/cancel on an end in a waitable set. Keep the runtime spellings + // explicit so unrelated synchronous-operation diagnostics cannot match. + [ + "waitable cannot be used synchronously while added to a waitable set", + [ + "future.cancel-write: synchronous cancel on an end that is in a waitable set", + "future.cancel-read: synchronous cancel on an end that is in a waitable set", + "stream.cancel-write: synchronous cancel on an end that is in a waitable set", + "stream.cancel-read: synchronous cancel on an end that is in a waitable set", + "synchronous future copy on an end that is in a waitable set", + "synchronous stream copy on an end that is in a waitable set", + ], + ], + // Pinned Wasmtime's guest_read/guest_write terminal-state checks + // (futures_and_streams.rs:3512-3514,3757-3759) and the runtime's CopyState.DONE + // checks (runtime/src/intrinsics/stream_builtins.ts:156-161) are identical; + // only the preposition differs. Do not include the future-write OR-category, + // whose message combines a successful prior write with peer drop. + [ + "cannot read after being notified that the writable end dropped", + ["cannot read from stream after being notified that the writable end dropped"], + ], + [ + "cannot write after being notified that the readable end dropped", + ["cannot write to stream after being notified that the readable end dropped"], + ], + // The same-instance non-numeric guard is the exact check on both sides: + // runtime/src/task/streams.ts:587-591,708-711,725-728 and pinned Wasmtime + // futures_and_streams.rs:3330-3335. Future/stream names are diagnostic only. + [ + "cannot read from and write to intra-component future/stream with non-numeric payload", + [ + "cannot read from and write to intra-component future", + "cannot read from and write to intra-component stream", + ], + ], ]; // Exported for the unit-test suite (tests/runner_unit_test.ts) to pin the diff --git a/harness/src/wasmtime-expectations.ts b/harness/src/wasmtime-expectations.ts index eb29855..8378444 100644 --- a/harness/src/wasmtime-expectations.ts +++ b/harness/src/wasmtime-expectations.ts @@ -115,48 +115,6 @@ export const WASMTIME_EXPECTATION_GROUPS: readonly WasmtimeExpectationGroup[] = { class: "diagnostic-mismatch", files: [ - { - file: "async/backpressure-overflow.json", - rows: [{ - lines: [36], - cause: - 'Error: expected trap "backpressure counter overflow", got "backpressure counter underflow"', - status: "failed", - }], - }, - { - file: "async/cancel-host.json", - rows: [{ - lines: [256], - cause: - 'Error: expected trap "`subtask.cancel` called after terminal status delivered", got "subtask.cancel on a subtask whose resolution was already delivered"', - status: "failed", - }], - }, - { - file: "async/cancel-sync-and-waitable.json", - rows: [{ - lines: [68], - cause: - 'Error: expected trap "waitable cannot be used synchronously while added to a waitable set", got "future.cancel-write: synchronous cancel on an end that is in a waitable set"', - status: "failed", - }, { - lines: [121], - cause: - 'Error: expected trap "waitable cannot be used synchronously while added to a waitable set", got "future.cancel-read: synchronous cancel on an end that is in a waitable set"', - status: "failed", - }, { - lines: [174], - cause: - 'Error: expected trap "waitable cannot be used synchronously while added to a waitable set", got "stream.cancel-write: synchronous cancel on an end that is in a waitable set"', - status: "failed", - }, { - lines: [227], - cause: - 'Error: expected trap "waitable cannot be used synchronously while added to a waitable set", got "stream.cancel-read: synchronous cancel on an end that is in a waitable set"', - status: "failed", - }], - }, { file: "async/future-read.json", rows: [{ @@ -166,70 +124,15 @@ export const WASMTIME_EXPECTATION_GROUPS: readonly WasmtimeExpectationGroup[] = status: "failed", }], }, - { - file: "async/intra-futures.json", - rows: [{ - lines: [55], - cause: - 'Error: expected trap "cannot read from and write to intra-component future/stream with non-numeric payload", got "cannot read from and write to intra-component future"', - status: "failed", - }], - }, - { - file: "async/intra-streams.json", - rows: [{ - lines: [56], - cause: - 'Error: expected trap "cannot read from and write to intra-component future/stream with non-numeric payload", got "cannot read from and write to intra-component stream"', - status: "failed", - }], - }, { file: "async/stream-cancel-finished-op.json", rows: [{ - lines: [232, 234, 236], - cause: - 'Error: expected trap "cannot read after being notified that the writable end dropped", got "cannot read from stream after being notified that the writable end dropped"', - status: "failed", - }, { - lines: [239, 241, 243], - cause: - 'Error: expected trap "cannot write after being notified that the readable end dropped", got "cannot write to stream after being notified that the readable end dropped"', - status: "failed", - }, { lines: [247, 249, 251], cause: 'Error: expected trap "cannot write after being notified that the readable end dropped", got "cannot write to future after previous write succeeded or readable end dropped"', status: "failed", }], }, - { - file: "async/subtask-wait.json", - rows: [{ - lines: [82], - cause: - 'Error: expected trap "wasm `unreachable` instruction executed", got "guest trapped: unreachable"', - status: "failed", - }], - }, - { - file: "async/sync-and-async-waitable.json", - rows: [{ - lines: [123], - cause: - 'Error: expected trap "waitable cannot be used synchronously while added to a waitable set", got "synchronous future copy on an end that is in a waitable set"', - status: "failed", - }], - }, - { - file: "async/sync-call-context-trap.json", - rows: [{ - lines: [47], - cause: - 'Error: expected trap "wasm `unreachable` instruction executed", got "guest trapped: unreachable"', - status: "failed", - }], - }, { file: "async/task-return-traps.json", rows: [{ @@ -256,16 +159,6 @@ export const WASMTIME_EXPECTATION_GROUPS: readonly WasmtimeExpectationGroup[] = cause: 'Error: expected trap "cannot write after being notified that the readable end dropped", got "cannot write to future after previous write succeeded or readable end dropped"', status: "failed", - }, { - lines: [643, 645, 647, 649], - cause: - 'Error: expected trap "cannot write after being notified that the readable end dropped", got "cannot write to stream after being notified that the readable end dropped"', - status: "failed", - }, { - lines: [652, 654, 658, 660], - cause: - 'Error: expected trap "cannot read after being notified that the writable end dropped", got "cannot read from stream after being notified that the writable end dropped"', - status: "failed", }], }, { @@ -295,15 +188,6 @@ export const WASMTIME_EXPECTATION_GROUPS: readonly WasmtimeExpectationGroup[] = status: "failed", }], }, - { - file: "trap.json", - rows: [{ - lines: [30], - cause: - 'Error: expected trap "wasm `unreachable` instruction executed", got "guest trapped: unreachable"', - status: "failed", - }], - }, { file: "types.json", rows: [{ diff --git a/harness/tests/runner_unit_test.ts b/harness/tests/runner_unit_test.ts index 2a8db79..c1c146e 100644 --- a/harness/tests/runner_unit_test.ts +++ b/harness/tests/runner_unit_test.ts @@ -262,3 +262,66 @@ Deno.test("trapMatches: an unrelated engine trap message does not falsely match "unrelated trap", ); }); + +Deno.test("trapMatches: verified diagnostic equivalents match only their named operations", () => { + const equivalents: Array<[string, string]> = [ + ["backpressure counter overflow", "backpressure counter underflow"], + [ + "`subtask.cancel` called after terminal status delivered", + "subtask.cancel on a subtask whose resolution was already delivered", + ], + [ + "waitable cannot be used synchronously while added to a waitable set", + "future.cancel-read: synchronous cancel on an end that is in a waitable set", + ], + [ + "waitable cannot be used synchronously while added to a waitable set", + "synchronous stream copy on an end that is in a waitable set", + ], + [ + "cannot read after being notified that the writable end dropped", + "cannot read from stream after being notified that the writable end dropped", + ], + [ + "cannot write after being notified that the readable end dropped", + "cannot write to stream after being notified that the readable end dropped", + ], + [ + "cannot read from and write to intra-component future/stream with non-numeric payload", + "cannot read from and write to intra-component future", + ], + [ + "wasm `unreachable` instruction executed", + "guest trapped: unreachable", + ], + ]; + for (const [expected, actual] of equivalents) { + assertEq(trapMatches(expected, actual), true, `${expected} / ${actual}`); + } +}); + +Deno.test("trapMatches: narrow diagnostic rows reject adjacent but different traps", () => { + const nonEquivalents: Array<[string, string]> = [ + ["integer overflow", "integer underflow"], + ["backpressure counter overflow", "reference count overflow"], + [ + "waitable cannot be used synchronously while added to a waitable set", + "wasm trap: deadlock detected: event loop cannot make further progress", + ], + [ + "cannot write after being notified that the readable end dropped", + "cannot write to future after previous write succeeded or readable end dropped", + ], + [ + "cannot read from and write to intra-component future/stream with non-numeric payload", + "cannot have concurrent operations active on a future/stream", + ], + [ + "uncaught exception propagated out of component", + "guest trapped: unreachable", + ], + ]; + for (const [expected, actual] of nonEquivalents) { + assertEq(trapMatches(expected, actual), false, `${expected} / ${actual}`); + } +});