From 8a0bec7b87d510a5a385f2c03b2b6c32490078cc Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 5 Aug 2020 20:37:25 +1000 Subject: [PATCH] libei: fix source removal on ei_disconnect The sink dispatch() loop gets the source from the epollfd data pointer, so unref'ing the source would cause it to be destroyed when we may try to access it later. Fix the whole source ownership properly, the first ref is owned by the epollfd and moves to the list of removed sources, the caller gets the second ref. Signed-off-by: Peter Hutterer --- src/libei.c | 1 + src/util-sources.c | 7 +++++-- src/util-sources.h | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libei.c b/src/libei.c index 0bfaace..150840b 100644 --- a/src/libei.c +++ b/src/libei.c @@ -357,6 +357,7 @@ ei_disconnect(struct ei *ei) /* FIXME: unroll the devices here */ ei_queue_disconnect_event(ei); ei->state = EI_STATE_DISCONNECTED; + source_remove(ei->source); ei->source = source_unref(ei->source); } diff --git a/src/util-sources.c b/src/util-sources.c index 52c2c87..99d746c 100644 --- a/src/util-sources.c +++ b/src/util-sources.c @@ -55,6 +55,7 @@ struct source { int fd; }; +OBJECT_IMPLEMENT_REF(source); OBJECT_IMPLEMENT_UNREF(source); OBJECT_IMPLEMENT_GETTER(source, fd, int); OBJECT_IMPLEMENT_GETTER(source, user_data, void*); @@ -72,6 +73,8 @@ source_remove(struct source *source) if (source->close_behavior == SOURCE_CLOSE_ON_REMOVE) source->fd = xclose(source->fd); } + /* Note: epollfd was the owner of the source, new owner is the removed + list */ list_remove(&source->link); list_append(&source->sink->sources_removed, &source->link); } @@ -105,7 +108,7 @@ source_add(struct sink *sink, int sourcefd, struct epoll_event e = { .events = EPOLLIN, - .data.ptr = source, + .data.ptr = source, /* epollfd is the owner of this source */ }; if (epoll_ctl(sink->epollfd, EPOLL_CTL_ADD, sourcefd, &e) < 0) { @@ -115,7 +118,7 @@ source_add(struct sink *sink, int sourcefd, list_append(&sink->sources, &source->link); - return source; + return source_ref(source); } struct source * diff --git a/src/util-sources.h b/src/util-sources.h index 03683be..bcd570e 100644 --- a/src/util-sources.h +++ b/src/util-sources.h @@ -43,6 +43,9 @@ typedef void (*source_dispatch_t)(struct source *source, void *user_data); */ void source_remove(struct source *source); +struct source * +source_ref(struct source *source); + /** * Unref source. When the last reference is dropped, the source is removed * from the sink and resources are released.