pipewire: module-zeroconf-discover: handle when AvahiWatch is freed while dispatching

When a particular AvahiWatch is being dispatched, it cannot
be freed because `watch_callback()` accesses it after
the callback.

Introduce a member (`dispatching`) to coordinate
the deferred freeing in that case.

The timeouts are not affected because the `AvahiTimeout`
object is not accessed after the callback is called.
This commit is contained in:
Barnabás Pőcze 2022-03-07 17:45:23 +01:00
parent 8dccfbce4c
commit 8fa4d5c43f

View file

@ -37,6 +37,7 @@ struct AvahiWatch {
AvahiWatchEvent events; AvahiWatchEvent events;
AvahiWatchCallback callback; AvahiWatchCallback callback;
void *userdata; void *userdata;
unsigned int dispatching;
}; };
struct AvahiTimeout { struct AvahiTimeout {
@ -65,9 +66,14 @@ static void watch_callback(void *data, int fd, uint32_t mask)
{ {
AvahiWatch *w = data; AvahiWatch *w = data;
w->dispatching += 1;
w->events = from_pw_events(mask); w->events = from_pw_events(mask);
w->callback(w, fd, w->events, w->userdata); w->callback(w, fd, w->events, w->userdata);
w->events = 0; w->events = 0;
if (--w->dispatching == 0 && !w->source)
free(w);
} }
static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event,
@ -103,9 +109,11 @@ static AvahiWatchEvent watch_get_events(AvahiWatch *w)
static void watch_free(AvahiWatch *w) static void watch_free(AvahiWatch *w)
{ {
struct impl *impl = w->impl; pw_loop_destroy_source(w->impl->loop, w->source);
pw_loop_destroy_source(impl->loop, w->source); w->source = NULL;
free(w);
if (!w->dispatching)
free(w);
} }
static void timeout_callback(void *data, uint64_t expirations) static void timeout_callback(void *data, uint64_t expirations)