From da6b1a8e4774234c2dbdd9f2875de21b41086d00 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 20 Apr 2012 14:22:51 +0300 Subject: [PATCH] tests: support testing fd inheritance over exec Add facility for testing how (many) file descriptors survive an exec. This allows implementing O_CLOEXEC tests. Signed-off-by: Pekka Paalanen --- tests/Makefile.am | 16 ++++++-- tests/exec-fd-leak-checker.c | 75 ++++++++++++++++++++++++++++++++++++ tests/sanity-test.c | 22 +++++++++++ tests/test-helpers.c | 12 ++++++ tests/test-runner.h | 3 ++ 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 tests/exec-fd-leak-checker.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 72247781..af76c5fe 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,4 @@ -TESTS = $(check_PROGRAMS) - - -check_PROGRAMS = \ +my_check_programs = \ sanity-test \ array-test \ map-test \ @@ -10,6 +7,12 @@ check_PROGRAMS = \ event-loop-test \ client-test +TESTS = $(my_check_programs) + +check_PROGRAMS = \ + $(my_check_programs) \ + exec-fd-leak-checker + test_runner_src = test-runner.c test-runner.h test-helpers.c sanity_test_SOURCES = sanity-test.c $(test_runner_src) @@ -25,3 +28,8 @@ LDADD = $(top_builddir)/src/libwayland-util.la \ $(top_builddir)/src/libwayland-server.la \ -lrt -ldl $(FFI_LIBS) +exec_fd_leak_checker_SOURCES = \ + exec-fd-leak-checker.c \ + test-runner.h \ + test-helpers.c +exec_fd_leak_checker_LDADD = diff --git a/tests/exec-fd-leak-checker.c b/tests/exec-fd-leak-checker.c new file mode 100644 index 00000000..66209ad5 --- /dev/null +++ b/tests/exec-fd-leak-checker.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2012 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "test-runner.h" + +static int +parse_count(const char *str, int *value) +{ + char *end; + long v; + + errno = 0; + v = strtol(str, &end, 0); + if ((errno == ERANGE && (v == LONG_MAX || v == LONG_MIN)) || + (errno != 0 && v == 0) || + (end == str) || + (*end != '\0')) { + return -1; + } + + if (v < 0 || v > INT_MAX) { + return -1; + } + + *value = v; + return 0; +} + +int main(int argc, char *argv[]) +{ + int expected; + + if (argc != 2) + goto help_out; + + if (parse_count(argv[1], &expected) < 0) + goto help_out; + + if (count_open_fds() == expected) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + +help_out: + fprintf(stderr, "Usage: %s N\n" + "where N is the expected number of open file descriptors.\n" + "This program exits with a failure if the number " + "does not match exactly.\n", argv[0]); + + return EXIT_FAILURE; +} diff --git a/tests/sanity-test.c b/tests/sanity-test.c index 389ee4c5..65e01447 100644 --- a/tests/sanity-test.c +++ b/tests/sanity-test.c @@ -93,3 +93,25 @@ FAIL_TEST(sanity_fd_leak) /* leak 2 file descriptors */ pipe(fd); } + +FAIL_TEST(sanity_fd_leak_exec) +{ + int fd[2]; + int nr_fds = count_open_fds(); + + /* leak 2 file descriptors */ + pipe(fd); + + exec_fd_leak_check(nr_fds); +} + +TEST(sanity_fd_exec) +{ + int fd[2]; + int nr_fds = count_open_fds(); + + /* create 2 file descriptors, that should pass over exec */ + pipe(fd); + + exec_fd_leak_check(nr_fds + 2); +} diff --git a/tests/test-helpers.c b/tests/test-helpers.c index 2cc5c7d6..4761b09e 100644 --- a/tests/test-helpers.c +++ b/tests/test-helpers.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "test-runner.h" @@ -50,3 +52,13 @@ count_open_fds(void) return count; } +void +exec_fd_leak_check(int nr_expected_fds) +{ + const char *exe = "./exec-fd-leak-checker"; + char number[16] = { 0 }; + + snprintf(number, sizeof number - 1, "%d", nr_expected_fds); + execl(exe, exe, number, (char *)NULL); + assert(0 && "execing fd leak checker failed"); +} diff --git a/tests/test-runner.h b/tests/test-runner.h index edcf5925..707504cc 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -34,4 +34,7 @@ struct test { int count_open_fds(void); +void +exec_fd_leak_check(int nr_expected_fds); /* never returns */ + #endif