echo-cancel: ignore remaining canceller messages after the module has been unloaded

Not ignoring the messages caused crashing due to accessing the userdata
after it had been freed.

BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=103528
This commit is contained in:
Tanu Kaskinen 2017-11-09 14:12:33 +02:00
parent d65974d850
commit 5f29b838ff

View file

@ -184,6 +184,7 @@ struct userdata;
struct pa_echo_canceller_msg { struct pa_echo_canceller_msg {
pa_msgobject parent; pa_msgobject parent;
bool dead;
struct userdata *userdata; struct userdata *userdata;
}; };
@ -1553,6 +1554,20 @@ static int canceller_process_msg_cb(pa_msgobject *o, int code, void *userdata, i
pa_assert(o); pa_assert(o);
msg = PA_ECHO_CANCELLER_MSG(o); msg = PA_ECHO_CANCELLER_MSG(o);
/* When the module is unloaded, there may still remain queued messages for
* the canceller. Messages are sent to the main thread using the master
* source's asyncmsgq, and that message queue isn't (and can't be, at least
* with the current asyncmsgq API) cleared from the canceller messages when
* module-echo-cancel is unloaded.
*
* The userdata may already have been freed at this point, but the
* asyncmsgq holds a reference to the pa_echo_canceller_msg object, which
* contains a flag to indicate that all remaining messages have to be
* ignored. */
if (msg->dead)
return 0;
u = msg->userdata; u = msg->userdata;
switch (code) { switch (code) {
@ -2149,6 +2164,9 @@ void pa__done(pa_module*m) {
if (u->ec->done) if (u->ec->done)
u->ec->done(u->ec); u->ec->done(u->ec);
if (u->ec->msg)
u->ec->msg->dead = true;
pa_xfree(u->ec); pa_xfree(u->ec);
} }
@ -2327,6 +2345,7 @@ int main(int argc, char* argv[]) {
} }
u.ec->done(u.ec); u.ec->done(u.ec);
u.ec->msg->dead = true;
out: out:
if (u.captured_file) if (u.captured_file)