]> granicus.if.org Git - libevent/commitdiff
Fix race in access to ev_res from event loop with event_active()
authorJames Synge <jamessynge@google.com>
Mon, 7 Aug 2017 15:06:28 +0000 (11:06 -0400)
committerAzat Khuzhin <a3at.mail@gmail.com>
Mon, 14 Aug 2017 21:09:04 +0000 (00:09 +0300)
Detected using ThreadSanitizer, resolved by capturing the value
of ev_res in a local variable while the event is locked, then
passing that captured variable to the callback.

TSAN report:
  I0728 14:35:09.822118   WARNING: ThreadSanitizer: data race (pid=815501)
  I0728 14:35:09.822186     Write of size 2 at 0x7b2c00001bf2 by thread T80 (mutexes: write M1110835549570434736):
  I0728 14:35:09.822248       #0 event_active_nolock_ libevent/event.c:2893:14 (0a2b90577e830d775300664df77d0b91+0x1fdab28)
  I0728 14:35:09.822316       #1 event_active libevent/event.c:2858:2 (0a2b90577e830d775300664df77d0b91+0x1fdd10e)
  I0728 14:35:09.822379       #2 Envoy::Event::TimerImpl::enableTimer(std::chrono::duration<long, std::ratio<1l, 1000l> > const&) envoy/source/common/event/timer_impl.cc:24:5 (0a2b90577e830d775300664df77d0b91+0x459fa0)
  ...

  I0728 14:35:09.824146     Previous read of size 2 at 0x7b2c00001bf2 by main thread:
  I0728 14:35:09.824232       #0 event_process_active_single_queue libevent/event.c:1646:33 (0a2b90577e830d775300664df77d0b91+0x1fdf83d)
  I0728 14:35:09.824350       #1 event_process_active libevent/event.c (0a2b90577e830d775300664df77d0b91+0x1fd9ad8)
  I0728 14:35:09.824445       #2 event_base_loop libevent/event.c:1961 (0a2b90577e830d775300664df77d0b91+0x1fd9ad8)
  I0728 14:35:09.824550       #3 Envoy::Event::DispatcherImpl::run(Envoy::Event::Dispatcher::RunType) envoy/source/common/event/dispatcher_impl.cc:166:3 (0a2b90577e830d775300664df77d0b91+0x4576d9)
  ...

Fixes: #543 (pull-request)
event.c

diff --git a/event.c b/event.c
index d2768793604b546f7a9d82fd8e9791376fd4fc11..98b1bc4ab6733ef21562b93ad1de89a50e9c3ef3 100644 (file)
--- a/event.c
+++ b/event.c
@@ -1641,10 +1641,12 @@ event_process_active_single_queue(struct event_base *base,
                        break;
                case EV_CLOSURE_EVENT: {
                        void (*evcb_callback)(evutil_socket_t, short, void *);
+                       short res;
                        EVUTIL_ASSERT(ev != NULL);
                        evcb_callback = *ev->ev_callback;
+                       res = ev->ev_res;
                        EVBASE_RELEASE_LOCK(base, th_base_lock);
-                       evcb_callback(ev->ev_fd, ev->ev_res, ev->ev_arg);
+                       evcb_callback(ev->ev_fd, res, ev->ev_arg);
                }
                break;
                case EV_CLOSURE_CB_SELF: {