Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memory leak of global locks (libevent-2.0.21-stable) #55

Closed
qidu opened this issue Apr 16, 2013 · 3 comments
Closed

memory leak of global locks (libevent-2.0.21-stable) #55

qidu opened this issue Apr 16, 2013 · 3 comments

Comments

@qidu
Copy link

qidu commented Apr 16, 2013

test code

void onTimeOut(evutil_socket_t fd, short event, void *arg)
{
        struct event_base* base = (struct event_base*)arg;
        event_base_loopbreak(base);
}
int main(int argc, char* argv[])
{
        int rc = evthread_use_pthreads();
        evthread_enable_lock_debuging();
        struct event_base* base = event_base_new();
        struct event* timeEvent = event_new(base, -1, EV_PERSIST, onTimeOut, base);
        struct timeval tv;
        evutil_timerclear(&tv);
        tv.tv_sec = 1;
        event_add(timeEvent, &tv);
        event_base_dispatch(base);
        event_free(timeEvent);
        event_base_free(base);
        return 0;
}

valgrind --leak-check=full --show-reachable=yes ./a.out
==15543== Memcheck, a memory error detector.
==15543== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==15543== Using LibVEX rev 1658, a library for dynamic binary translation.
==15543== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==15543== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==15543== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==15543== For more details, rerun with: -v
==15543==
==15543==
==15543== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 1)
==15543== malloc/free: in use at exit: 120 bytes in 3 blocks.
==15543== malloc/free: 14 allocs, 11 frees, 1,776 bytes allocated.
==15543== For counts of detected errors, rerun with: -v
==15543== searching for pointers to 3 not-freed blocks.
==15543== checked 206,968 bytes.
==15543==
==15543== 120 bytes in 3 blocks are still reachable in loss record 1 of 1
==15543== at 0x4A05809: malloc (vg_replace_malloc.c:149)
==15543== by 0x4E61ED1: evthread_posix_lock_alloc (evthread_pthread.c:46)
==15543== by 0x4C2AB37: event_global_setup_locks_ (event.c:2894)
==15543== by 0x4E61CE3: evthread_use_pthreads (evthread_pthread.c:187)
==15543== by 0x400A57: main (in /root/dev/a.out)
==15543==
==15543== LEAK SUMMARY:
==15543== definitely lost: 0 bytes in 0 blocks.
==15543== possibly lost: 0 bytes in 0 blocks.
==15543== still reachable: 120 bytes in 3 blocks.
==15543== suppressed: 0 bytes in 0 blocks.

@qidu
Copy link
Author

qidu commented Apr 16, 2013

We can add following patches to fix the bug
--------------------------------------------------------------------patch of signal.c------------------------------------------------------------------

--- /root/dev/orig/libevent-2.0.21-stable/signal.c  2012-11-02 23:57:00.000000000 +0800
+++ /root/dev/libevent-2.0.21-stable/signal.c   2013-04-16 15:27:31.000000000 +0800
@@ -439,7 +439,14 @@
 int
 evsig_global_setup_locks_(const int enable_locks)
 {
    EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
    return 0;
 }
+
+int
+evsig_global_free_locks_(const int enable_locks)
+{
+   EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
+}
 #endif

--------------------------------------------------------------------patch of evutil_rand.c------------------------------------------------------------------

--- /root/dev/orig/libevent-2.0.21-stable/evutil_rand.c 2012-08-02 23:36:53.000000000 +0800
+++ /root/dev/libevent-2.0.21-stable/evutil_rand.c  2013-04-16 15:27:19.000000000 +0800
@@ -118,9 +118,16 @@
 int
 evutil_secure_rng_global_setup_locks_(const int enable_locks)
 {
    EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0);
    return 0;
 }
+
+int
+evutil_secure_rng_global_free_locks_(const int enable_locks)
+{
+   EVTHREAD_FREE_LOCK(arc4rand_lock, 0);
+}
 #endif

 int

------------------------------------------------------------patch of event.c---------------------------------------------------------------------------------

--- /root/dev/orig/libevent-2.0.21-stable/event.c   2012-11-17 08:22:19.000000000 +0800
+++ /root/dev/libevent-2.0.21-stable/event.c    2013-04-16 15:30:15.000000000 +0800
@@ -788,7 +789,12 @@
    EVTHREAD_FREE_LOCK(base->th_base_lock, EVTHREAD_LOCKTYPE_RECURSIVE);
    EVTHREAD_FREE_COND(base->current_event_cond);

+   if(!current_base) {
+       event_global_free_locks_(0);
+   }
+
    mm_free(base);
 }

 /* reinitialize the event base after a fork */
@@ -2887,6 +2895,16 @@
        return -1;
    return 0;
 }
+
+int 
+event_global_free_locks_(const int enable_locks)
+{
+   evutil_secure_rng_global_free_locks_(0);
+   evsig_global_free_locks_(0);
+#ifndef _EVENT_DISABLE_DEBUG_MODE
+   EVTHREAD_FREE_LOCK(_event_debug_map_lock, 0);
+#endif
+}
 #endif

 void

@qidu qidu closed this as completed Apr 16, 2013
@qidu qidu reopened this Apr 16, 2013
@nmathewson
Copy link
Member

This part is broken:

+   if(!current_base) {
+       event_global_free_locks_(0);
+   }

If someone creates two event_bases, and frees the second one, this will free the global locks.

Libevent 2.1 already has a fix for this in the libevent_global_shutdown() function.

@qidu
Copy link
Author

qidu commented Apr 17, 2013

OK, i see, current_base is not a right flag for releasing global locks.
Calling the external interface "libevent_global_shutdown" explicitly would be better for users.
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants