[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] [patch] more testcases



Here are some patches.

0001 fires without following fixes
aff6ba1 Fix request_finished memory leak with debugging turned on.
9b724b2 Fix evsig_dealloc memory leak with debugging turned on.

0002 is just a preparation for 0003

0003 fires with current codebase but, seems, it should not. I'm sorry,
I can't produce a nice fix right now, so I'm just sharing the testcase
at this moment. :)

And the last question: should I send further patches to ML or via
github pull request?

--
WBRBW, Leonid Evdokimov
xmpp:leon@xxxxxxxxxxxx && http://darkk.net.ru
tel:+79816800702 && tel:+79050965222
From 7a616e13a318a0380a0f298a0779c996883cf4d1 Mon Sep 17 00:00:00 2001
From: Leonid Evdokimov <leon@xxxxxxxxxxxx>
Date: Tue, 18 Oct 2011 17:49:40 +0400
Subject: [PATCH 1/3] Test for commit aff6ba1

---
 test/regress_dns.c |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 116 insertions(+), 0 deletions(-)

diff --git a/test/regress_dns.c b/test/regress_dns.c
index 01cb0db..19581ef 100644
--- a/test/regress_dns.c
+++ b/test/regress_dns.c
@@ -1625,6 +1625,119 @@ gaic_launch(struct event_base *base, struct evdns_base *dns_base)
 	++pending;
 }
 
+static int allocated_chunks = 0;
+
+static void*
+cnt_malloc(size_t sz)
+{
+	allocated_chunks += 1;
+	return malloc(sz);
+}
+
+static void*
+cnt_realloc(void *old, size_t sz)
+{
+	if (!old)
+		allocated_chunks += 1;
+	if (!sz)
+		allocated_chunks -= 1;
+	return realloc(old, sz);
+}
+
+static void
+cnt_free(void *ptr)
+{
+	allocated_chunks -= 1;
+	return free(ptr);
+}
+
+struct testleak_env_t {
+	struct event_base* base;
+	struct evdns_base* dns_base;
+	struct evdns_request* req;
+	struct generic_dns_callback_result r;
+};
+
+static void*
+testleak_setup(const struct testcase_t *testcase)
+{
+	struct testleak_env_t* env;
+
+	allocated_chunks = 0;
+	event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free);
+	event_enable_debug_mode();
+
+	env = calloc(1, sizeof(struct testleak_env_t));
+	env->base = event_base_new();
+	env->dns_base = evdns_base_new(env->base, 0);
+	env->req = evdns_base_resolve_ipv4(
+		env->dns_base, "example.com", DNS_QUERY_NO_SEARCH,
+		generic_dns_callback, &env->r);
+	return env;
+}
+
+static int
+testleak_cleanup(const struct testcase_t *testcase, void *env_)
+{
+	int ok = 0;
+	struct testleak_env_t* env = env_;
+	/* FIXME: that's `1' because of event_debug_map_HT_GROW */
+	tt_int_op(allocated_chunks, ==, 1);
+	ok = 1;
+end:
+	if (env->dns_base)
+		evdns_base_free(env->dns_base, 0);
+	if (env->base)
+		event_base_free(env->base);
+	if (env)
+		free(env);
+	return ok;
+}
+
+static struct testcase_setup_t testleak_funcs = {
+	testleak_setup, testleak_cleanup
+};
+
+static void
+test_dbg_leak_cancel(void *env_)
+{
+	/* cancel, loop, free/dns, free/base */
+	struct testleak_env_t* env = env_;
+	int send_err_shutdown = 1;
+	evdns_cancel_request(env->dns_base, env->req);
+	env->req = 0;
+
+	/* `req` is freed in callback, that's why one loop is required. */
+	event_base_loop(env->base, EVLOOP_NONBLOCK);
+
+	/* send_err_shutdown means nothing as soon as our request is
+	 * already canceled */
+	evdns_base_free(env->dns_base, send_err_shutdown);
+	env->dns_base = 0;
+	event_base_free(env->base);
+	env->base = 0;
+}
+
+static void
+test_dbg_leak_shutdown(void *env_)
+{
+	/* free/dns, loop, free/base */
+	struct testleak_env_t* env = env_;
+	int send_err_shutdown = 1;
+
+	/* `req` is freed both with `send_err_shutdown` and without it,
+	 * the only difference is `evdns_callback` call */
+	env->req = 0;
+
+	evdns_base_free(env->dns_base, send_err_shutdown);
+	env->dns_base = 0;
+
+	/* `req` is freed in callback, that's why one loop is required */
+	event_base_loop(env->base, EVLOOP_NONBLOCK);
+	event_base_free(env->base);
+	env->base = 0;
+}
+
 static void
 test_getaddrinfo_async_cancel_stress(void *ptr)
 {
@@ -1702,6 +1815,9 @@ struct testcase_t dns_testcases[] = {
 	{ "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress,
 	  TT_FORK, NULL, NULL },
 
+	{ "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL },
+	{ "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL },
+
 	END_OF_TESTCASES
 };
 
-- 
1.7.5.4

From 79bcd81586f2e1bd0bf8bb7fd11630b9a68c7ebb Mon Sep 17 00:00:00 2001
From: Leonid Evdokimov <leon@xxxxxxxxxxxx>
Date: Wed, 19 Oct 2011 17:44:17 +0400
Subject: [PATCH 2/3] More detailed message in case of libevent self-debugging
 failure.

---
 event.c |   24 ++++++++++++++++--------
 1 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/event.c b/event.c
index 9064f89..cecba2b 100644
--- a/event.c
+++ b/event.c
@@ -250,8 +250,10 @@ HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
 			dent->added = 1;				\
 		} else {						\
 			event_errx(_EVENT_ERR_ABORT,			\
-			    "%s: noting an add on a non-setup event %p", \
-			    __func__, (ev));				\
+			    "%s: noting an add on a non-setup event %p" \
+			    " (events: 0x%x, fd: %d, flags: 0x%x)",	\
+			    __func__, (ev), (ev)->ev_events,		\
+			    (ev)->ev_fd, (ev)->ev_flags);		\
 		}							\
 		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
 	}								\
@@ -268,8 +270,10 @@ HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
 			dent->added = 0;				\
 		} else {						\
 			event_errx(_EVENT_ERR_ABORT,			\
-			    "%s: noting a del on a non-setup event %p", \
-			    __func__, (ev));				\
+			    "%s: noting a del on a non-setup event %p"	\
+			    " (events: 0x%x, fd: %d, flags: 0x%x)",	\
+			    __func__, (ev), (ev)->ev_events,		\
+			    (ev)->ev_fd, (ev)->ev_flags);		\
 		}							\
 		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
 	}								\
@@ -284,8 +288,10 @@ HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
 		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
 		if (!dent) {						\
 			event_errx(_EVENT_ERR_ABORT,			\
-			    "%s called on a non-initialized event %p",	\
-			    __func__, (ev));				\
+			    "%s called on a non-initialized event %p"	\
+			    " (events: 0x%x, fd: %d, flags: 0x%x)",	\
+			    __func__, (ev), (ev)->ev_events,		\
+			    (ev)->ev_fd, (ev)->ev_flags);		\
 		}							\
 		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
 	}								\
@@ -300,8 +306,10 @@ HT_GENERATE(event_debug_map, event_debug_entry, node, hash_debug_entry,
 		dent = HT_FIND(event_debug_map, &global_debug_map, &find); \
 		if (dent && dent->added) {				\
 			event_errx(_EVENT_ERR_ABORT,			\
-			    "%s called on an already added event %p",	\
-			    __func__, (ev));				\
+			    "%s called on an already added event %p"	\
+			    " (events: 0x%x, fd: %d, flags: 0x%x)",	\
+			    __func__, (ev), (ev)->ev_events,		\
+			    (ev)->ev_fd, (ev)->ev_flags);		\
 		}							\
 		EVLOCK_UNLOCK(_event_debug_map_lock, 0);		\
 	}								\
-- 
1.7.5.4

From db1e7c404be1e83c424b1f2c2d816647f7ff7c4e Mon Sep 17 00:00:00 2001
From: Leonid Evdokimov <leon@xxxxxxxxxxxx>
Date: Wed, 19 Oct 2011 17:46:08 +0400
Subject: [PATCH 3/3] Some failing tests for self-debugging during
 event_reinit.

---
 test/regress.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/test/regress.c b/test/regress.c
index f22f01f..5342e2a 100644
--- a/test/regress.c
+++ b/test/regress.c
@@ -883,6 +883,54 @@ test_fork(void)
 }
 
 static void
+nop_signal_cb(evutil_socket_t fd, short event, void *arg)
+{
+}
+
+static int mainloop_cfg_st = EVENT_BASE_FLAG_NOLOCK;
+static int mainloop_cfg_mt = 0;
+
+static void
+test_fork_dbg(void* ptr)
+{
+	struct basic_test_data* env = ptr;
+	int *mainloop_cfg = env->setup_data;
+	struct event_config* cfg;
+	struct event_base* base;
+	struct event sig_ev;
+	int pid, status, ok = 0;
+
+	event_enable_debug_mode();
+	if (mainloop_cfg) {
+		cfg = event_config_new();
+		tt_ptr_op(cfg, !=, NULL);
+		event_config_set_flag(cfg, *mainloop_cfg);
+		base = event_base_new_with_config(cfg);
+	} else {
+		base = event_base_new();
+	}
+	tt_ptr_op(base, !=, NULL);
+	evsignal_assign(&sig_ev, base, SIGUSR1, nop_signal_cb, NULL);
+	tt_int_op(evsignal_add(&sig_ev, NULL), ==, 0);
+
+	if ((pid = fork()) == 0) {
+		tt_int_op(event_reinit(base), ==, 0);
+		tt_int_op(evsignal_del(&sig_ev), ==, 0);
+		tt_int_op(event_base_dispatch(base), ==, 1);
+		event_base_free(base);
+		exit(76);
+	}
+	sleep(1);
+	tt_int_op(waitpid(pid, &status, 0), !=, -1);
+	tt_int_op(WEXITSTATUS(status), ==, 76);
+
+	ok = 1;
+end:
+	if (!ok)
+		exit(1);
+}
+
+static void
 signal_cb_sa(int sig)
 {
 	test_ok = 2;
@@ -2358,6 +2406,9 @@ struct testcase_t main_testcases[] = {
 
 #ifndef _WIN32
 	LEGACY(fork, TT_ISOLATED),
+	{ "fork_dbg", test_fork_dbg, TT_FORK, &basic_setup, NULL },
+	{ "fork_dbg_st", test_fork_dbg, TT_FORK, &basic_setup, &mainloop_cfg_st },
+	{ "fork_dbg_mt", test_fork_dbg, TT_FORK, &basic_setup, &mainloop_cfg_mt },
 #endif
 	END_OF_TESTCASES
 };
-- 
1.7.5.4