Skip to content

Fix crash when a texture file fails to load on an async worker thread - #116

Open
scottsheppeard wants to merge 1 commit into
PathOfBuildingCommunity:masterfrom
scottsheppeard:fix-async-texture-upload-fallback-upstream
Open

Fix crash when a texture file fails to load on an async worker thread#116
scottsheppeard wants to merge 1 commit into
PathOfBuildingCommunity:masterfrom
scottsheppeard:fix-async-texture-upload-fallback-upstream

Conversation

@scottsheppeard

Copy link
Copy Markdown

Problem

r_tex_c::LoadFile()'s failed-load fallback (missing or unreadable texture file) calls Upload() directly from the texture manager's worker thread. GL work is only valid on the thread owning the context, which is why the successful async load path enqueues via manager->EnqueueTextureUpload() and lets the main thread perform the upload in ProcessPendingTextureUploads() — but the fallback path bypasses that mechanism.

This is easy to hit in practice: PoB's passive tree sprite loading references TreeData/PassiveMasteryConnectedButton.png, which doesn't exist in the PathOfBuilding repo, so every failed async texture takes this path. On the macOS port (ANGLE/Metal) it's a deterministic startup SIGSEGV in GL_GenTextures:

EXC_BAD_ACCESS (SIGSEGV), KERN_INVALID_ADDRESS at 0x0
libGLESv2.dylib   GL_GenTextures
libSimpleGraphic  r_tex_c::Upload(image_c&, int)
libSimpleGraphic  r_tex_c::LoadFile()
libSimpleGraphic  t_manager_c::ThreadProc()

On other backends it's a latent thread-safety bug at best.

Fix

When TF_ASYNC is set, route the placeholder upload through the same pending-upload queue as the success path; the synchronous path is unchanged. flags is reset to TF_NOMIPMAP before enqueueing to preserve the previous Upload(*raw, TF_NOMIPMAP) GL behaviour.

Verified on an M-series MacBook Pro against stevschmid/PathOfBuilding-Mac's engine build (same code): previously crashed deterministically at startup; with the patch, PoE1 and PoE2 dev trees both start and run normally, with the missing file degrading to the default placeholder texture as intended.

🤖 Generated with Claude Code

r_tex_c::LoadFile()'s failed-load fallback (missing or unreadable file)
called Upload() directly from the texture manager's worker thread. The GL
context belongs to the main thread, so this crashes in ANGLE's
GL_GenTextures with a null-deref (observed as a startup SIGSEGV on macOS
when the PoB passive tree references TreeData/PassiveMasteryConnectedButton.png,
which does not exist).

Route the placeholder upload through the pending-upload queue exactly like
the successful async load path a few lines above, so the main thread
performs the GL work in ProcessPendingTextureUploads().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant