summaryrefslogtreecommitdiff
path: root/source3/lib/events.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/events.c')
-rw-r--r--source3/lib/events.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/source3/lib/events.c b/source3/lib/events.c
index 7a06ad0829..75aa250726 100644
--- a/source3/lib/events.c
+++ b/source3/lib/events.c
@@ -105,12 +105,29 @@ bool run_events(struct tevent_context *ev,
if ((ev->timer_events != NULL)
&& (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
+ /* this older events system did not auto-free timed
+ events on running them, and had a race condition
+ where the event could be called twice if the
+ talloc_free of the te happened after the callback
+ made a call which invoked the event loop. To avoid
+ this while still allowing old code which frees the
+ te, we need to create a temporary context which
+ will be used to ensure the te is freed. We also
+ remove the te from the timed event list before we
+ call the handler, to ensure we can't loop */
+
+ struct tevent_timer *te = ev->timer_events;
+ TALLOC_CTX *tmp_ctx = talloc_new(ev);
DEBUG(10, ("Running timed event \"%s\" %p\n",
ev->timer_events->handler_name, ev->timer_events));
- ev->timer_events->handler(ev, ev->timer_events, now,
- ev->timer_events->private_data);
+ DLIST_REMOVE(ev->timer_events, te);
+ talloc_steal(tmp_ctx, te);
+
+ te->handler(ev, te, now, te->private_data);
+
+ talloc_free(tmp_ctx);
return true;
}