Skip to content

WASM rethrow instruction is generated with a wrong index #114600

Closed
@purplesyringa

Description

@purplesyringa

This is a wasm target, built with -fwasm-exceptions. Reproducer:

#include <cstdio>

__attribute__((noinline)) void print_current() noexcept {
  try {
    throw;
  } catch (int x) {
    printf("%d\n", x);
  }
}

struct Dropper {
  ~Dropper() {
    try {
      throw 1;
    } catch (...) {
      print_current();
    }
  }
};

int main() {
  try {
    Dropper dropper;
    throw 2;
  } catch (...) {
    print_current();
  }
}

Expected output: 1 2, actual output: 1 1.

(I'm using emcc -O2 -fwasm-exceptions test.cpp for testing if that's important.)

The problem is in the codegen for main:

Wasm IR
(func (;6;) (type 11) (result i32)
  (local i32 i32)
  global.get 0
  local.set 1
  call 22
  local.tee 0
  i32.const 2
  i32.store
  try ;; label = @1
    local.get 0
    call 28
  catch_all
    local.get 1
    global.set 0
    call 22
    local.tee 0
    i32.const 1
    i32.store
    try ;; label = @2
      try ;; label = @3
        local.get 0
        call 28
      catch 0
        local.set 0
        local.get 1
        global.set 0
        local.get 0
        call 29
        drop
        call 5
        call 30
        try ;; label = @4
          try ;; label = @5
            rethrow 2 (;@3;)
          catch 0
            local.set 0
            local.get 1
            global.set 0
            local.get 0
            call 29
            drop
            call 5
            try ;; label = @6
              call 30
            delegate 5
            i32.const 0
            return
          end
          unreachable
        delegate 3
        unreachable
      end
    catch_all
      local.get 1
      global.set 0
      call 37
      unreachable
    end
    unreachable
  end
  unreachable
)

In pseudocode, simplified:

try:
    throw(2)
catch_all:
    try:
        try:
            throw(1)
        catch:
            print_current()
            rethrow(0)
    catch:
        print_current()

So rethrow(0) rethrows the same exception as has just been handled, so the same exception object is caught twice. rethrow(2) would work correctly. The current behavior leads to all sorts of memory corruption and hard-to-debug state.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions