Attempting to trigger identical events will corrupt the TAILQ
structure and lead to a segfault. This segfault was exhibited
by a new test case where NOTE_TRIGGER fires multiple times
before an attempt to read the event is made.
---
This patch is also available for download at:
http://bogomips.org/libkqueue.git/patch/?id=8701d4959
src/common/knote.c | 9 ++++++++-
test/user.c | 22 ++++++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/src/common/knote.c b/src/common/knote.c
index 74aa36d..02c64bf 100644
--- a/src/common/knote.c
+++ b/src/common/knote.c
@@ -109,7 +109,14 @@ knote_lookup_data(struct filter *filt, intptr_t data)
void
knote_enqueue(struct filter *filt, struct knote *kn)
{
- /* XXX-FIXME: check if the knote is already on the eventlist */
+ struct knote *cur;
+
+ /* check if the knote is already on the eventlist */
+ TAILQ_FOREACH(cur, &filt->kf_event, event_ent) {
+ if (cur == kn)
+ return;
+ }
+
TAILQ_INSERT_TAIL(&filt->kf_event, kn, event_ent);
}
diff --git a/test/user.c b/test/user.c
index fc88a78..2ec580b 100644
--- a/test/user.c
+++ b/test/user.c
@@ -92,6 +92,27 @@ test_kevent_user_oneshot(void)
test_no_kevents(kqfd);
}
+static void
+test_kevent_user_multi_trigger_merged(void)
+{
+ struct kevent kev;
+ int i;
+
+ test_no_kevents(kqfd);
+
+ kevent_add(kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
+
+ for (i = 0; i < 10; i++)
+ kevent_add(kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ kev.flags = EV_CLEAR;
+ kev.fflags &= ~NOTE_FFCTRLMASK;
+ kev.fflags &= ~NOTE_TRIGGER;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ test_no_kevents(kqfd);
+}
+
#if HAVE_EV_DISPATCH
void
test_kevent_user_dispatch(void)
@@ -141,6 +162,7 @@ test_evfilt_user(int _kqfd)
test(kevent_user_get);
test(kevent_user_disable_and_enable);
test(kevent_user_oneshot);
+ test(kevent_user_multi_trigger_merged);
#if HAVE_EV_DISPATCH
test(kevent_user_dispatch);
#endif
--
Eric Wong