Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Catching traps #206

@MikeInnes

Description

@MikeInnes

In general this proposal looks great. However, I don't understand why traps can't be caught. The proposal states:

The rationale for this is that in general traps are not locally recoverable and are not needed to be handled in local scopes like try-catch.

But surely the idea of exceptions is to provide non-local error recovery. Meanwhile, traps can be handled by JS (in the browser), so they are not treated as fundamentally unrecoverable elsewhere.

True catch-alls are not that common, but important examples could include:

  • a REPL or JIT which compiles and runs user code on the fly;
  • an Erlang-like process model where tasks may crash entirely, but a supervisor can reboot as needed.

In these cases errors should unwind the stack, running catch blocks for destructors and cleanup, so that the program can continue from a sensible state. You'd also want to catch and display the stack trace, or even launch a debug UI. If traps can't do this, we must instead crash the application and ask the user to restart.

I can think of three broad workarounds in those cases:

  • Have the compiler turn traps into exceptions, by bounds checking pointer loads and so on. Aside from any performance cost, though, this wouldn't help foreign calls to separately-compiled code.
  • Use a JS exception handler when a true catch-all is needed. However, this complicates implementation (some kind of shadow stack would be needed so the supervisor can run destructors) and precludes supporting WASI-only runtimes, where a trap would still have to crash the process.
  • The above but with memory isolation, so that if a task fails we just throw out its instance. But this is a worst of both worlds (performance hit and no WASI) that also doesn't account for external resources (eg GPU memory handles).

There's an example of using a JS handler in the wat2wasm demo, though it's of course simpler for not having to handle cleanup or shared memory.

So, why are traps a special case? I'd prefer to be able to catch them, but if there's some deeper reason why that's not possible, perhaps that rationale could be made clearer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions