Plex app crashes when idle on my new mac mini - here's the bug

Server Version#:
Player Version#: 1.112.0

If I leave the app idle it eventually crashes with the following

Crash Analysis: Plex EXC_BAD_ACCESS (SIGSEGV)

TL;DR

This is a use-after-free or stale pointer dereference in the OpenGL/AppKit rendering path, triggered during a window resize event (specifically entering/exiting fullscreen tile mode). The faulting address tells the whole story.


Faulting Address Dissection

KERN_INVALID_ADDRESS at 0x0000000300003c00

The address 0x300003c00 is characteristic: it sits in a large unmapped gap between:

unused __TEXT   2e43c8000-2e43cc000   (ends ~0x2e43cc000)
GAP OF 0x23ca8000 BYTES
CoreAnimation   308074000-308f04000   (starts ~0x308074000)

The value 0x300003c00 is suspicious in a specific way — look at x1 and far registers:

x1:  0x0000000300003c00   ← the bad pointer, passed as source to memmove
far: 0x0000000300003c00   ← FAR confirms this is the faulting load address
x8:  0x0000000000003c00   ← note: low 16 bits = 0x3c00

0x3c00 = 15360 decimal, which is consistent with a pixel buffer stride or size (e.g., 3840 × 4 bytes per pixel / something similar for a 5K display). The upper bits 0x300000000 look like a corrupted or zeroed-out pointer — the object was freed and its memory partially cleared, leaving a dangling base address with a small legitimate-looking offset surviving in a field.


Crash Call Stack (Thread 0, bottom-up causality)

Frame 28: -[NSWindow _setFrameCommon:display:fromServer:]
  ← window is being resized

Frame 29: -[_NSFullScreenContentController reshapeContentForTileFrame:...]
  ← this is a fullscreen tile resize (Stage Manager or split-screen)

Frame 30-32: _NSFullScreenSpace tile notification infrastructure
  ← SkyLight posts a CGS distributed notification for tile reshape

Frames 33-44: CFNotificationCenter → CFRunLoop dispatch
  ← the notification arrives on the main thread via the run loop

Frame 23-26: CALayer display → CA::Transaction::commit
  ← the reshape triggers a Core Animation display commit

Frame 1: -[NSSoftwareSurface frontBuffer]   ← fetches the front IOSurface buffer
Frame 0: _platform_memmove + 52             ← CRASH: reads from the bad pointer

The crash is memmove reading from x1 = 0x300003c00. At frame 1, NSSoftwareSurface frontBuffer is returning (or computing) a pointer to the front buffer backing store. That pointer is garbage.


Root Cause

NSSoftwareSurface holds a reference to an IOSurface-backed pixel buffer. During the fullscreen tile reshape, the surface was reallocated or deallocated to accommodate the new frame geometry, but Plex’s OpenGL context (via the legacy NSOpenGLContext/NSCGLSurface path) still held a stale reference to the old surface.

When the resize notification fires synchronously on the main thread and triggers a CA commit, AppKit tries to blit from the (now-freed) front buffer into the new surface — and memmove faults on the stale pointer.

The key contributing factors:

  1. Plex is using the deprecated NSOpenGLContext / OpenGL rendering path (frames 4-6: GLEngine → CGLFlushDrawable → NSOpenGLContext flushBuffer). This API family is deprecated since macOS 10.14 and has received minimal compatibility work on Apple Silicon.

  2. Qt 6.2.4 + libqcocoa is bridging between Qt’s RHI (QRhi::endFrame → QOpenGLContext::swapBuffers) and the legacy macOS OpenGL surface stack. Qt 6.2.4 is old (2022); later Qt versions moved away from this path for macOS.

  3. macOS 26.3 (Tahoe beta based on the build number pattern) — this is a pre-release OS. AppKit’s fullscreen tiling/Stage Manager notifications have changed in Tahoe, and the _NSFullScreenSpace tile reshape path may have a new timing or ordering that exposes the race.


The Race

The sequence:

1. SkyLight posts tile-resize notification
2. AppKit reshapes window frame, frees/replaces NSSoftwareSurface backing
3. Notification also triggers CA display commit
4. CA commit → NSCGLSurface flushRect → NSSoftwareSurface frontBuffer
5. frontBuffer returns stale pointer to freed IOSurface memory
6. memmove → SIGSEGV

This is a window between the surface teardown and the completion of the CA transaction commit, hit because the Qt/OpenGL path issues a flushBuffer that AppKit then routes through the software surface path rather than going directly through Metal compositing.


Confirming Evidence

  • esr: 0x92000007 — Data Abort, byte read, Translation fault (page not mapped, not a permission fault). This is consistent with a freed IOSurface whose pages have been returned to the VM system.

  • x0 = 0x032d024000 — this is the destination address (in a valid CoreAnimation region, ~0x308074000 range). Valid write target, invalid read source.

  • x2 = 0x1fa4000 = 33,038,336 bytes ≈ 31.5 MB — that’s the copy size. At 5K resolution (5120×2880×4 = 58.9 MB) this is plausible for a partial buffer blit.

  • The process had been running for 580,000 seconds (~6.7 days) before this crash — so this isn’t a startup issue but a long-running state that finally hit the race.


Not the Cause

  • The PMS threads (PlexMediaServer, mpv, Lua scripts) are all cleanly blocked on condition variables or poll — not involved.

  • QtWebEngine threads are also clean. The embedded Chromium stack is idle.

  • No memory pressure issues (VM summary shows 99% unallocated writable region).


Fix Path

This is fundamentally Plex’s problem to fix — they need to:

  1. Migrate off NSOpenGLContext to Metal or at minimum ensure the Qt RHI swap chain is properly synchronized with AppKit surface lifecycle during window geometry changes.

  2. Update Qt — 6.2.4 is ancient; later Qt versions (6.5+) have better macOS surface management.

  3. Short-term mitigation: avoid entering fullscreen tile mode with Plex open, or disable hardware acceleration in Plex settings if that option exists.

If you want to report this, the actionable signal for the Plex team is: -[NSSoftwareSurface frontBuffer] returns stale IOSurface pointer during _NSFullScreenSpace tile reshape, causing memmove fault in the legacy NSOpenGLContext flush path.