From 6f7854a72b46b1defb3c0e9237f6fd9002d69cdc Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 14 Mar 2011 16:53:23 +0000 Subject: [PATCH] Don't report file descriptors as "leaked" if they were already open This is necessary to run the regression tests under valgrind (if telling it to output to a dedicated fd), gdb, fakeroot etc. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=35173 --- bus/test-main.c | 9 ++++- dbus/dbus-message-private.h | 5 +- dbus/dbus-message-util.c | 86 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/bus/test-main.c b/bus/test-main.c index cab7530..a8039d5 100644 --- a/bus/test-main.c +++ b/bus/test-main.c @@ -54,6 +54,8 @@ check_memleaks (const char *name) } #endif /* DBUS_BUILD_TESTS */ +static DBusInitialFDs *initial_fds = NULL; + static void test_pre_hook (void) { @@ -62,16 +64,21 @@ test_pre_hook (void) && (!bus_selinux_pre_init () || !bus_selinux_full_init ())) die ("could not init selinux support"); + + initial_fds = _dbus_check_fdleaks_enter (); } static char *progname = ""; + static void test_post_hook (void) { if (_dbus_getenv ("DBUS_TEST_SELINUX")) bus_selinux_shutdown (); check_memleaks (progname); - _dbus_check_fdleaks(); + + _dbus_check_fdleaks_leave (initial_fds); + initial_fds = NULL; } int diff --git a/dbus/dbus-message-private.h b/dbus/dbus-message-private.h index 57888fa..c5e3b3e 100644 --- a/dbus/dbus-message-private.h +++ b/dbus/dbus-message-private.h @@ -138,8 +138,9 @@ dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter, int first_arg_type, va_list var_args); - -void _dbus_check_fdleaks(void); +typedef struct DBusInitialFDs DBusInitialFDs; +DBusInitialFDs *_dbus_check_fdleaks_enter (void); +void _dbus_check_fdleaks_leave (DBusInitialFDs *fds); /** @} */ diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c index f972c8a..2d2b6fe 100644 --- a/dbus/dbus-message-util.c +++ b/dbus/dbus-message-util.c @@ -138,12 +138,66 @@ check_memleaks (void) } } -void -_dbus_check_fdleaks(void) -{ +#ifdef __linux__ +struct DBusInitialFDs { + fd_set set; +}; +#endif +DBusInitialFDs * +_dbus_check_fdleaks_enter (void) +{ #ifdef __linux__ + DIR *d; + DBusInitialFDs *fds; + + /* this is plain malloc so it won't interfere with leak checking */ + fds = malloc (sizeof (DBusInitialFDs)); + _dbus_assert (fds != NULL); + + /* This works on Linux only */ + + if ((d = opendir("/proc/self/fd"))) + { + struct dirent *de; + + while ((de = readdir(d))) + { + long l; + char *e = NULL; + int fd; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol(de->d_name, &e, 10); + _dbus_assert(errno == 0 && e && !*e); + fd = (int) l; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + FD_SET (fd, &fds->set); + } + + closedir(d); + } + + return fds; +#else + return NULL; +#endif +} + +void +_dbus_check_fdleaks_leave (DBusInitialFDs *fds) +{ +#ifdef __linux__ DIR *d; /* This works on Linux only */ @@ -173,12 +227,19 @@ _dbus_check_fdleaks(void) if (fd == dirfd(d)) continue; + if (FD_ISSET (fd, &fds->set)) + continue; + _dbus_warn("file descriptor %i leaked in %s.\n", fd, __FILE__); _dbus_assert_not_reached("fdleaks"); } closedir(d); } + + free (fds); +#else + _dbus_assert (fds == NULL); #endif } @@ -1000,6 +1061,9 @@ _dbus_message_test (const char *test_data_dir) int v_UNIX_FD; #endif char **decomposed; + DBusInitialFDs *initial_fds; + + initial_fds = _dbus_check_fdleaks_enter (); message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", "/org/freedesktop/TestPath", @@ -1394,7 +1458,8 @@ _dbus_message_test (const char *test_data_dir) _dbus_message_loader_unref (loader); check_memleaks (); - _dbus_check_fdleaks(); + _dbus_check_fdleaks_leave (initial_fds); + initial_fds = _dbus_check_fdleaks_enter (); /* Check that we can abandon a container */ message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", @@ -1458,16 +1523,23 @@ _dbus_message_test (const char *test_data_dir) } check_memleaks (); - _dbus_check_fdleaks(); + _dbus_check_fdleaks_leave (initial_fds); /* Now load every message in test_data_dir if we have one */ if (test_data_dir == NULL) return TRUE; - return dbus_internal_do_not_use_foreach_message_file (test_data_dir, + initial_fds = _dbus_check_fdleaks_enter (); + + if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir, (DBusForeachMessageFileFunc) dbus_internal_do_not_use_try_message_file, - NULL); + NULL)) + _dbus_assert_not_reached ("foreach_message_file test failed"); + + _dbus_check_fdleaks_leave (initial_fds); + + return TRUE; } #endif /* DBUS_BUILD_TESTS */ -- 1.7.4.1