Skip to content

Fix hang on OBS exit caused by use-after-free in destroy path - #174

Merged
exeldro merged 3 commits into
exeldro:masterfrom
reximus-bbs:fix-hang-on-exit
Apr 13, 2026
Merged

exeldro merged 3 commits into
exeldro:masterfrom
reximus-bbs:fix-hang-on-exit

Conversation

@reximus-bbs

Copy link
Copy Markdown
Contributor

source_record_filter_destroy queued force_stop_output_task via
run_queued and then called source_record_delayed_destroy directly,
which could free the context before the queued tasks ran. On OBS exit
the queue often stops processing before those tasks fire, leaving
outputs in a stopping state that OBS waits on — causing the hang.

Introduces stop_output_sync() which force-stops and releases an
output inline, and uses it in the closing paths (filter_remove,
destroy, and the closing branches of filter_update). Non-closing
stops (toggle-off, tick restart/disable) keep the async path.
delayed_destroy is removed and its cleanup inlined into destroy.

source_record_filter_destroy queued force_stop_output_task via
run_queued and then called source_record_delayed_destroy directly,
which could free the context before the queued tasks ran. During
OBS exit the task queue often stops processing before the queued
stops fire, leaving outputs in a stopping state that OBS waits on,
causing the entire application to hang on close.

Introduce stop_output_sync() which force-stops and releases an
output inline (after disconnecting the remove_filter signal), and
use it in all closing paths: filter_remove, destroy, and the
closing branches of filter_update. The non-closing stop paths
(user-initiated toggle off, tick restart/disable) still use the
async force_stop_output_task path. delayed_destroy is removed and
its cleanup logic inlined into destroy.
@exeldro

exeldro commented Apr 12, 2026

Copy link
Copy Markdown
Owner

With these changes I get a crash when I try to close OBS, switch scene collection or remove the filter when replay buffer on source record is active. The source record was on the active scene.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@reximus-bbs

Copy link
Copy Markdown
Contributor Author

Pushed a fix. stop_output_sync was unconditionally releasing outputs — during exit release_output_stopped skips the release and lets the output manager clean up. Added the same exiting check. Also added an encoder inactivity wait in destroy before releasing, matching what delayed_destroy did via re-queue.

Tested on OBS 32.1.1 with replay buffer active — close OBS, switch scene collection, remove filter. No crash, no hang. What OBS version are you building against?

@exeldro

exeldro commented Apr 12, 2026

Copy link
Copy Markdown
Owner

I test on OBS 32.1.1
The crash on exiting OBS is now replaced by a reference leak of the output.
Still a crash when I remove the source record filter or switch scene collection.

obs_output_force_stop is async for encoded outputs; releasing
immediately races with end_data_capture_thread still using encoders.
Let destroy handle release after encoder inactivity poll.

Fixes crash on filter remove and scene collection switch with
replay buffer active. Fixes output reference leak on exit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@exeldro

exeldro commented Apr 12, 2026

Copy link
Copy Markdown
Owner

The code seems to work now, I plan to do a code review in the next days

@reximus-bbs

Copy link
Copy Markdown
Contributor Author

Thanks. The last commit (f689e67) is the one to review. Moved obs_output_release out of stop_output_sync into destroy, after the encoder inactivity poll. No more early release racing end_data_capture_thread, and outputs always get released on exit. There's also a test-harness branch with some simplified lifecycle tests (not end-to-end) if that's useful.

Thanks for the plugin btw, we use it all the time.

@exeldro
exeldro merged commit b65531d into exeldro:master Apr 13, 2026
6 of 7 checks passed
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