backtrace¶
backtrace
¶
Stop a torch C++ error from segfaulting the process when it is raised inside an interleaving greenlet.
nnsight runs intervention code in greenlets (see
nnsight.intervention.interleaver). greenlet time-shares one OS thread
stack by copying stack slices in and out of the heap on every switch. When a
torch op raises a c10 error while a worker greenlet is running, torch's
c10::Error constructor eagerly captures a C++ backtrace via glibc
backtrace() -- which walks the raw machine stack. It walks the worker's
live frames fine, reaches greenlet's switch trampoline (which has no clean DWARF
unwind info), and then continues into the shared-stack region below, now holding
stale bytes from another worker's saved/restored slice. libgcc's unwinder
computes a garbage frame there and SIGSEGVs -- so a plain shape error in a user's
intervention becomes a hard process crash instead of a normal Python exception.
The one fragile operation is that backtrace() call. This module removes it:
it overwrites glibc backtrace() in-process so it returns 0 (no frames)
without walking the stack. torch then builds the error with an empty C++
backtrace and it propagates as an ordinary Python exception. Python tracebacks
and error messages are unaffected; only torch's (rarely used) C++ backtrace
string is emptied. This is the in-process equivalent of LD_PRELOAD-ing a
no-op backtrace().
Gated by CONFIG.APP.DISABLE_CPP_BACKTRACE (env
NNSIGHT_DISABLE_CPP_BACKTRACE). Only glibc on x86-64 Linux is patched -- that
is where the crash lives; musl's backtrace() is already a no-op stub and
other platforms use different unwinders, so they are left untouched. Every step
fails safe: if anything is unexpected the process is left exactly as it was.
install
¶
Neutralize glibc backtrace() so a c10 error on a greenlet can't crash.
Returns True if the guard is in place (including on a repeat call), and
False if it was skipped -- unsupported platform, no glibc backtrace,
or a page could not be made writable. Idempotent and never raises.