[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[Libevent-users] [PATCH] Fix possible memory leaks with debugging turned on.
I think, I've found couple of memory leaks in libevent debugging code:
the event was not properly unregistered from debug hashtable.
I run evdns-example using $(valgrind --leak-check=full
--show-reachable=yes), I'm attaching three valgrind logs:
evdns-example.no-0004.no-0005.log - without 0004-*.patch
evdns-example.yes-0004.no-0005.log - only 0004-*.patch was applied
evdns-example.yes-0004.yes-0005.log - both 0004-*.patch and
0005-*.patch were applied
Probably, the leaks are not real leaks but my misunderstanding of
debugging code, so review the patches, please :)
Also, feel free to include evdns-example.c as sample of proper evdns
cleanup if you find it useful. I think, that cleanup is not trivial.
--
WBRBW, Leonid Evdokimov
xmpp:leon@xxxxxxxxxxxx && http://darkk.net.ru
tel:+79816800702 && tel:+79050965222
From 573b0ee284e19d2f399e67d58179252e2f8f7166 Mon Sep 17 00:00:00 2001
From: Leonid Evdokimov <darkk@xxxxxxxxxxxxxx>
Date: Thu, 11 Aug 2011 03:10:08 +0400
Subject: [PATCH 4/5] Fix evsig_dealloc memory leak with debugging turned on.
---
signal.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/signal.c b/signal.c
index 72c0847..2079204 100644
--- a/signal.c
+++ b/signal.c
@@ -400,9 +400,11 @@ evsig_dealloc(struct event_base *base)
int i = 0;
if (base->sig.ev_signal_added) {
event_del(&base->sig.ev_signal);
- event_debug_unassign(&base->sig.ev_signal);
base->sig.ev_signal_added = 0;
}
+ /* debug event is created in evsig_init/event_assign even when
+ * ev_signal_added == 0, so unassign is required */
+ event_debug_unassign(&base->sig.ev_signal);
for (i = 0; i < NSIG; ++i) {
if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
--
1.7.4.1
From d95b04da4174f3843321518c3b220671979e5827 Mon Sep 17 00:00:00 2001
From: Leonid Evdokimov <darkk@xxxxxxxxxxxxxx>
Date: Thu, 11 Aug 2011 03:24:06 +0400
Subject: [PATCH 5/5] Fix request_finished memory leak with debugging turned on.
---
evdns.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/evdns.c b/evdns.c
index b6c2916..d7a3093 100644
--- a/evdns.c
+++ b/evdns.c
@@ -647,6 +647,8 @@ request_finished(struct request *const req, struct request **head, int free_hand
} else {
base->global_requests_waiting--;
}
+ /* it was initialized during request_new / evtimer_assign */
+ event_debug_unassign(&req->timeout_event);
if (!req->request_appended) {
/* need to free the request data on it's own */
--
1.7.4.1
#include <event2/dns.h>
#include <event2/event.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
void evdns_callback(int result, char type, int count, int ttl, void *addresses, void *arg)
{
(void)type;
(void)count;
(void)ttl;
(void)addresses;
(void)arg;
puts(evdns_err_to_string(result));
}
void test_cancel()
{
struct event_base* evbase = event_base_new();
assert(evbase);
struct evdns_base *evdns = evdns_base_new(evbase, 1);
assert(evdns);
struct evdns_request* req = evdns_base_resolve_ipv4(
evdns, "www.google.com", DNS_QUERY_NO_SEARCH, evdns_callback, 0);
evdns_cancel_request(evdns, req);
req = 0;
// `req` is freed in callback, that's why one loop is required.
event_base_loop(evbase, EVLOOP_NONBLOCK);
int send_err_shutdown = 1; // means nothing as soon as our request is already canceled
evdns_base_free(evdns, send_err_shutdown);
evdns = 0;
event_base_free(evbase);
evbase = 0;
}
void test_shutdown(int send_err_shutdown)
{
struct event_base* evbase = event_base_new();
assert(evbase);
struct evdns_base *evdns = evdns_base_new(evbase, 1);
assert(evdns);
struct evdns_request* req = evdns_base_resolve_ipv4(
evdns, "www.google.com", DNS_QUERY_NO_SEARCH, evdns_callback, 0);
req = 0;
// `req` is freed both with `send_err_shutdown` and without it, the only
// difference is `evdns_callback` call
evdns_base_free(evdns, send_err_shutdown);
evdns = 0;
// `req` is freed in callback, that's why one loop is required.
event_base_loop(evbase, EVLOOP_NONBLOCK);
event_base_free(evbase);
evbase = 0;
}
int main(int argc, char* argv[])
{
if (argc != 3) {
puts("Usage: evdns-example <use_debug> <testcase>");
return 1;
}
if (atoi(argv[1])) {
// may leak a bit, at least it leaves traces in valgrind --leak-check=full --show-reachable=yes
event_enable_debug_mode();
}
switch (atoi(argv[2])) {
case 1:
test_cancel();
break;
case 2:
test_shutdown(0);
break;
case 3:
test_shutdown(1);
break;
default:
puts("Unknown testcase");
}
return 0;
}