Skip to content

Signal handler violates async-signal-safety by calling malloc via TLS access #12787

@jbachorik

Description

@jbachorik

Summary

Wasmtime's SIGSEGV/SIGBUS trap handler (trap_handler in crates/wasmtime/src/runtime/vm/sys/unix/signals.rs) violates POSIX async-signal-safety requirements by:

  1. Accessing thread-local storage via tls::with(), which can trigger __tls_get_addr
  2. __tls_get_addr calls malloc() on first TLS access for a thread
  3. malloc() is not async-signal-safe and can deadlock if the interrupted code was holding malloc's internal lock

Reproduction

This causes deadlocks when wasmtime is used alongside other software that:

  • Installs its own SIGSEGV handlers (e.g., Java profilers using safefetch)
  • Triggers SIGSEGV intentionally for safe memory probing

The deadlock occurs when:

  1. Thread A is inside malloc() holding its internal lock
  2. SIGSEGV arrives (from safefetch or other intentional fault)
  3. Wasmtime's trap_handler runs
  4. tls::with() → __tls_get_addr → malloc()
  5. malloc() tries to acquire the lock already held → DEADLOCK

Stack trace from deadlock

  #7  __tls_get_addr () at ../sysdeps/x86_64/tls_get_addr.S:55 
  #8  wasmtime_runtime::traphandlers::tls::raw::get ()
  #9  wasmtime_runtime::traphandlers::unix::trap_handler ()
  #10 <signal handler called>
  #11 safefetch64_impl ()  // intentional SIGSEGV for safe memory access
  ...
  #27 sysmalloc ()
  #28 _int_malloc ()
  #29 __GI___libc_malloc ()  // original malloc call that holds the lock

The code comment acknowledges this

From signals.rs:
"The main current requirement of the signal handler in terms of stack space is that malloc/realloc are called to create a Backtrace of wasm frames."

Suggested fix

  1. Use tls_eager_initialize() on thread creation to ensure TLS is initialized before any signal can arrive
  2. Consider using a signal-safe TLS mechanism (e.g., dedicated pthread key with pre-allocated storage)
  3. Avoid any allocation in the signal handler fast path - defer backtrace creation

Environment

  • wasmtime-jni 0.19.0
  • Linux x86_64
  • glibc

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