Skip to content

fix: do not interpose Plex C++ exceptions by default - #28

Open
johoja12 wants to merge 1 commit into
cgnl:mainfrom
johoja12:fix/plex-exception-interposer
Open

johoja12 wants to merge 1 commit into
cgnl:mainfrom
johoja12:fix/plex-exception-interposer

Conversation

@johoja12

Copy link
Copy Markdown

Problem

Plex 1.43.4 uses libc++ and LLVM's unwinder. Exporting __cxa_throw from the preload shim inserts an incompatible interposed frame between routine Plex throws and their intended catches. In our isolated QNAP migration, GDB caught std::domain_error: Invalid uuid length in the PMS GTP thread. The value was adaptive_bitrate, a normal non-UUID input that Plex is expected to handle; with the shim export it aborted instead. The same fork author reproduced the failure with an unauthenticated /media/providers request, which should return 401 and keep running.

Fix

Carry the mediactl fork's 6db8e37 commit, preserving its original author. Gate the exported __cxa_throw hook behind an off-by-default exception-hook feature, retaining it for deliberate diagnostics.

Verification

The mediactl shim built for x86-64 and its dynamic symbol table contains no exported __cxa_throw. An isolated migration trial with the same patched Plex binary and a fresh PostgreSQL database is in progress; production remains on SQLite.

Related: #27 addresses separate vfork and Boost codecvt startup failures.

Interposing __cxa_throw puts a frame belonging to this library between every
throw in Plex and the catch that was meant to handle it, and Plex does not
survive that. The first exception the process throws is fatal whatever it
was, which is why this surfaced as three unrelated looking crashes -- all of
them exceptions Plex throws and handles perfectly well on its own:

    std::out_of_range: basic_string
    std::domain_error: Invalid uuid length
    UnauthorizedException: HTTP status code 401

One request reproduces it in a minute, with no Kubernetes and no cluster:

    GET /media/providers, no token
      plain Plex, own SQLite      -> 401, keeps running
      shim + fresh PostgreSQL     -> terminates, uncaught
      without this hook           -> 401, keeps running

A throw/catch test built against libstdc++ passes with the hook loaded, which
is how it survived review: libstdc++ and libgcc are a matched pair and the
forward is harmless between them. Plex is libc++ with LLVM's unwinder, and
that is the pairing that breaks.

The hook and the __cxa_throw backtrace that depends on it are kept behind an
"exception-hook" feature, off by default, because the backtrace is what found
the NULL column-type bug and is worth having for the next one. Turning it on
means accepting that Plex will die on its first exception.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants