Bug 89672 - PulseAudio crashes when remote device is unpaired during A2DP streaming
Summary: PulseAudio crashes when remote device is unpaired during A2DP streaming
Status: RESOLVED FIXED
Alias: None
Product: PulseAudio
Classification: Unclassified
Component: modules (show other bugs)
Version: unspecified
Hardware: ARM Linux (All)
: medium major
Assignee: pulseaudio-bugs
QA Contact: pulseaudio-bugs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-19 09:17 UTC by Sagar Nm
Modified: 2015-03-27 13:37 UTC (History)
4 users (show)

See Also:
i915 platform:
i915 features:


Attachments
Call Stack (3.79 KB, text/plain)
2015-03-19 09:17 UTC, Sagar Nm
Details
PulseAudio Logs (7.28 KB, text/plain)
2015-03-19 09:39 UTC, Sagar Nm
Details
This patch avoids the crash issue explained in this bug (2.33 KB, patch)
2015-03-19 11:00 UTC, Sagar Nm
Details | Splinter Review
Proposed Patch to Fix the PA crash due to stop_thread() recursive. (2.33 KB, text/plain)
2015-03-20 11:21 UTC, Rakesh M K
Details
Fix: Prevent calling pa_rtpoll_free() for a NULL rtpoll (5.18 KB, patch)
2015-03-24 11:53 UTC, Sagar Nm
Details | Splinter Review
PATCH v1: Prevent calling pa_rtpoll_free() for a NULL rtpoll (5.31 KB, patch)
2015-03-27 10:35 UTC, Sagar Nm
Details | Splinter Review

Description Sagar Nm 2015-03-19 09:17:22 UTC
Created attachment 114464 [details]
Call Stack

- PulseAudio is running in the local device (DUT) which is acting as A2DP Source

- Connect a Bluetooth Headset to DUT

- Start A2DP streaming

- Goto settings menu in DUT and UNPAIR the remote device during active music streaming

- PulseAudio crashes sometimes
Comment 1 Sagar Nm 2015-03-19 09:39:12 UTC
Created attachment 114468 [details]
PulseAudio Logs
Comment 2 Sagar Nm 2015-03-19 11:00:55 UTC
Created attachment 114469 [details] [review]
This patch avoids the crash issue explained in this bug

This bug looks like a timing issue where POLLHUP has happened during rendering.

This patch may not be the proper fix, but the crash is actually avoided with the attached changes.
Comment 3 Rakesh M K 2015-03-19 13:46:40 UTC
In addition to the issue explained by Mr. Sagar, please find the root cause for the issue.

//When remote headset is unpaired or disconnected, blueZ will call "ClearConfiguration" Dbus method. Which will update the transport state to disconnected.

16:19:35.027+0900   375   375 I PULSEAUDIO: [pulseaudio] bluez5-util.c: dbus: path=/MediaEndpoint/A2DPSource, interface=org.bluez.MediaEndpoint1, member=ClearConfiguration
16:19:35.027+0900   375   375 I PULSEAUDIO: [pulseaudio] bluez5-util.c: Clearing transport /org/bluez/hci0/dev_00_18_09_24_68_25/fd0 profile a2dp_sink

//Due to which the STOP thread will be handled.
transport_state_changed_cb() -> pa_card_set_profile() -> set_profile_cb() -> stop_thread().

//When Stop thread handling is in progress, rendering thread will post the "BLUETOOTH_MESSAGE_IO_THREAD_FAILED" due to audio packet pa_write() fail.
thread_func() -> a2dp_process_render() -> goto fail; -> pa_asyncmsgq_post(with IO thread fail).
16:19:35.032+0900   375   620 E PULSEAUDIO: [bluetooth] module-bluez5-device.c: Failed to write data to socket: Broken pipe
16:19:35.032+0900   375   620 I PULSEAUDIO: [bluetooth] module-bluez5-device.c: IO thread failed

//Since processing of message is done inside the stop_thread() which internally calls the Stop_thread() one more time.
stop_thread() -> pa_thread_mq_done() -> pa_asyncmsgq_flush() -> pa_asyncmsgq_dispatch() -> device_process_msg() for  BLUETOOTH_MESSAGE_IO_THREAD_FAILED -> pa_card_set_profile() -> set_profile_cb() -> stop_thread().
Comment 4 Rakesh M K 2015-03-20 11:21:47 UTC
Created attachment 114486 [details]
Proposed Patch to Fix the PA crash due to stop_thread() recursive.

Proposed Patch to avoid the PA crash due to stop_thread() recursive.

When remote headset is unpaired or disconnected, blueZ
will call "ClearConfiguration" Dbus method. Which will update
the transport state to disconnected. Due to which the STOP thread
will be handled. When Stop thread handling is in progress, rendering
thread will post the "BLUETOOTH_MESSAGE_IO_THREAD_FAILED" due to
audio packet pa_write() fail. Since processing of message is done
inside the stop_thread() which internally calls the Stop_thread()
one more time. Further access pa msgQue memory which is already
freed will leads to the pulseAudio crash.
This patch with avoid the recursive call of stop thread.
Comment 5 David Henningsson 2015-03-23 13:40:23 UTC
Hi,

In general, stopping recursion is good and as such I don't mind the patch by Rakesh M K, but I think we should also make pa_thread_mq_done save against recursion.

http://lists.freedesktop.org/archives/pulseaudio-discuss/2015-March/023450.html
Comment 6 Sagar Nm 2015-03-24 11:53:36 UTC
Created attachment 114580 [details] [review]
Fix: Prevent calling pa_rtpoll_free() for a NULL rtpoll

Hello David,

We encountered a crash issue while verifying your below change:
http://lists.freedesktop.org/archives/pulseaudio-discuss/2015-March/023450.html

We have attached a patch that addressed the crash issue observed. Please share your opinion on the same.

Thanks,
Sagar N
Comment 7 David Henningsson 2015-03-27 09:28:31 UTC
Comment on attachment 114580 [details] [review]
Fix: Prevent calling pa_rtpoll_free() for a NULL rtpoll

Review of attachment 114580 [details] [review]:
-----------------------------------------------------------------

Sorry for the slow reply. Are you 100% certain that messages dispatched by pa_thread_mq_done will not need the rtpoll? If not, perhaps the following is better:

    if (u->rtpoll)
        pa_thread_mq_done(&u->thread_mq); 
    /* pa_thread_mq_done might recurse into stop_thread again, hence this extra "if (u->rtpoll)" check */
    if (u->rpoll) {
        pa_rtpoll_free(u->rtpoll);
        u->rtpoll = NULL;
    }
Comment 8 Arun Raghavan 2015-03-27 10:31:43 UTC
Do we have any other cases where we expect pa_thread_mq_done() to be called recursively?

It seems to me that it is stop_thread() that should be safe against multiple calls (maybe tear down the thread first, and if it's already been torn down, just return).
Comment 9 Sagar Nm 2015-03-27 10:35:34 UTC
Created attachment 114666 [details] [review]
PATCH v1: Prevent calling pa_rtpoll_free() for a NULL rtpoll

Hi David,

We agree with your comment. Its safer to have an extra check.

Regards,
Sagar Nm
Comment 10 Tanu Kaskinen 2015-03-27 10:44:08 UTC
The rtpoll object is the event loop of the IO thread. No other thread has any business accessing it (except when creating and freeing it). When pa_thread_mq_done() is called, the IO thread has already been torn down, so there's no risk of needing the rtpoll object inside pa_thread_mq_done().
Comment 11 David Henningsson 2015-03-27 13:37:15 UTC
After some discussion, two patches have now been committed; "Fix: Prevent calling pa_rtpoll_free() for a NULL rtpoll" and "thread-mq: Make pa_thread_mq_done more robust".

These two patches should resolve the bug, if I understand things correctly. Please reopen the bug if this is not correct. Thanks!


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.