Cherry-pick upstream PR #5045: fix AudioMediaPlayer use-after-free on async EOF callback - #17
Merged
darshan-verkada merged 1 commit intoJul 15, 2026
Conversation
Destroying an AudioMediaPlayer (e.g. mid-playback or right after EOF) can crash in eof_cb() on a freed object. file_get_frame() publishes an async PJMEDIA_EVENT_CALLBACK at EOF, dispatched later on the event-worker thread via file_on_event() -> cb2 (= AudioMediaPlayer::eof_cb, usr_data = this). ~AudioMediaPlayer() -> pjsua_player_destroy() -> pjmedia_port_destroy() only dec_ref's the port's group lock (the conference bridge still holds a ref and removes the port asynchronously), so file_on_destroy() -- and its pjmedia_event_unsubscribe() -- run long after the C++ object is freed. The queued/in-flight callback then dereferences freed memory. The faulting address differs every time (jump through a freed vtable), sharing this stack: #0 <freed> #1 libpjsua2 AudioMediaPlayer::eof_cb() media.cpp #2 libpjmedia file_on_event() wav_player.c #3 libpjmedia event_mgr_distribute_events() event.c #4 libpjmedia event_worker_thread() event.c Cancel the subscription synchronously while the object is still alive: clearing the eof cb via set_eof_cb2(port, NULL, NULL) now unsubscribes from the media event, which blocks on the event manager cb_mutex until any in-flight callback drains and prevents future dispatch. ~AudioMediaPlayer() calls it before teardown. cb2 is cleared before the unsubscribe so a concurrent file_get_frame() at EOF cannot re-arm the subscription in the gap. cb_mutex is recursive, so destroying from inside onEof2() is safe; destroying from another thread while holding a lock onEof2() also takes can deadlock (documented on the destructor). Applies to both wav_player.c and wav_playlist.c. Addresses pjsip#4812.
MattMacGregor
approved these changes
Jul 15, 2026
darshan-verkada
merged commit Jul 15, 2026
8574fa1
into
intercom/release-2-15
19 of 31 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cherry-picks upstream pjproject PR pjsip#5045 onto
intercom/release-2-15.Upstream PR: pjsip#5045
Fixes an
AudioMediaPlayeruse-after-free where the async EOF event(
eof_cb) could be dispatched on the event-worker thread against analready-freed C++ object. The destructor now cancels the EOF subscription
synchronously (unsubscribe drains any in-flight callback via the event
manager
cb_mutex) before teardown.The conflict in
pjsip/src/pjsua2/media.cppwas resolved to keep thefork-local
id = PJSUA_INVALID_ID;guard (prevents double conf-portremoval) alongside the upstream EOF-cancel logic.