X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=tests%2Fregression%2Fkernel%2Fselect_poll_epoll.cpp;h=f4e947497123b7b5c8e02a32230ad8035e7df095;hb=cd9adb8b829564212158943a0d279bb35322ab30;hp=fb72f6e5a582c48899752acbeeb3bd20966ccc39;hpb=f46376a14da2eb796690cb4e718e8b213839d6ea;p=lttng-tools.git diff --git a/tests/regression/kernel/select_poll_epoll.cpp b/tests/regression/kernel/select_poll_epoll.cpp index fb72f6e5a..f4e947497 100644 --- a/tests/regression/kernel/select_poll_epoll.cpp +++ b/tests/regression/kernel/select_poll_epoll.cpp @@ -5,34 +5,43 @@ * */ -#include +/* + * This test voluntarily does buffer overflows and stack overruns, disable + * source fortification. + */ +#ifdef _FORTIFY_SOURCE +#undef _FORTIFY_SOURCE +#endif + +#include +#include + +#include +#include #include +#include +#include #include -#include -#include -#include -#include -#include +#include +#include #include #include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #define BUF_SIZE 256 -#define NB_FD 1 -#define MAX_FDS 2047 -#define NR_ITER 1000 /* for stress-tests */ +#define NB_FD 1 +#define MAX_FDS 2047 +#define NR_ITER 1000 /* for stress-tests */ -#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */ +#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */ #define BIG_SELECT_FD 1022 #define MSEC_PER_USEC 1000 @@ -56,34 +65,34 @@ static void epoll_pwait_int_max(FILE *validation_output_file); static void ppoll_concurrent_write(FILE *validation_output_file); static void epoll_pwait_concurrent_munmap(FILE *validation_output_file); -typedef void (*test_case_cb)(FILE *output_file); +using test_case_cb = void (*)(FILE *); -static const struct test_case { +namespace { +const struct test_case { test_case_cb run; bool produces_validation_info; int timeout; -} test_cases [] = -{ +} test_cases[] = { { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 }, { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 }, - { .run = pselect_invalid_fd, .produces_validation_info = false }, - { .run = test_ppoll_big, .produces_validation_info = false }, - { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false }, - { .run = pselect_invalid_pointer, .produces_validation_info = false }, - { .run = ppoll_fds_ulong_max, .produces_validation_info = false }, - { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true }, - { .run = epoll_pwait_int_max, .produces_validation_info = true }, - { .run = ppoll_concurrent_write, .produces_validation_info = false }, - { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true }, + { .run = pselect_invalid_fd, .produces_validation_info = false, .timeout = 0 }, + { .run = test_ppoll_big, .produces_validation_info = false, .timeout = 0 }, + { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false, .timeout = 0 }, + { .run = pselect_invalid_pointer, .produces_validation_info = false, .timeout = 0 }, + { .run = ppoll_fds_ulong_max, .produces_validation_info = false, .timeout = 0 }, + { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true, .timeout = 0 }, + { .run = epoll_pwait_int_max, .produces_validation_info = true, .timeout = 0 }, + { .run = ppoll_concurrent_write, .produces_validation_info = false, .timeout = 0 }, + { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true, .timeout = 0 }, }; struct ppoll_thread_data { struct pollfd *ufds; int value; }; +} /* namespace */ -static -void test_select_big(void) +static void test_select_big() { fd_set rfds, wfds, exfds; struct timeval tv; @@ -108,7 +117,7 @@ void test_select_big(void) if (timeout > 0) { ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv); } else { - ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL); + ret = select(fd2 + 1, &rfds, &wfds, &exfds, nullptr); } if (ret == -1) { @@ -129,8 +138,7 @@ end: return; } -static -void test_pselect(void) +static void test_pselect() { fd_set rfds; struct timespec tv; @@ -144,9 +152,9 @@ void test_pselect(void) tv.tv_nsec = timeout * MSEC_PER_NSEC; if (timeout > 0) { - ret = pselect(1, &rfds, NULL, NULL, &tv, NULL); + ret = pselect(1, &rfds, nullptr, nullptr, &tv, nullptr); } else { - ret = pselect(1, &rfds, NULL, NULL, NULL, NULL); + ret = pselect(1, &rfds, nullptr, nullptr, nullptr, nullptr); } if (ret == -1) { @@ -159,8 +167,7 @@ void test_pselect(void) } } -static -void test_select(void) +static void test_select() { fd_set rfds; struct timeval tv; @@ -174,9 +181,9 @@ void test_select(void) tv.tv_usec = timeout * MSEC_PER_USEC; if (timeout > 0) { - ret = select(1, &rfds, NULL, NULL, &tv); + ret = select(1, &rfds, nullptr, nullptr, &tv); } else { - ret = select(1, &rfds, NULL, NULL, NULL); + ret = select(1, &rfds, nullptr, nullptr, nullptr); } if (ret == -1) { @@ -189,15 +196,14 @@ void test_select(void) } } -static -void test_poll(void) +static void test_poll() { struct pollfd ufds[NB_FD]; char buf[BUF_SIZE]; int ret; ufds[0].fd = wait_fd; - ufds[0].events = POLLIN|POLLPRI; + ufds[0].events = POLLIN | POLLPRI; ret = poll(ufds, 1, timeout); @@ -211,8 +217,7 @@ void test_poll(void) } } -static -void test_ppoll(void) +static void test_ppoll() { struct pollfd ufds[NB_FD]; char buf[BUF_SIZE]; @@ -220,17 +225,16 @@ void test_ppoll(void) struct timespec ts; ufds[0].fd = wait_fd; - ufds[0].events = POLLIN|POLLPRI; + ufds[0].events = POLLIN | POLLPRI; if (timeout > 0) { ts.tv_sec = 0; ts.tv_nsec = timeout * MSEC_PER_NSEC; - ret = ppoll(ufds, 1, &ts, NULL); + ret = ppoll(ufds, 1, &ts, nullptr); } else { - ret = ppoll(ufds, 1, NULL, NULL); + ret = ppoll(ufds, 1, nullptr, nullptr); } - if (ret < 0) { PERROR("ppoll"); } else if (ret > 0) { @@ -241,8 +245,7 @@ void test_ppoll(void) } } -static -void test_ppoll_big(FILE *validation_output_file __attribute__((unused))) +static void test_ppoll_big(FILE *validation_output_file __attribute__((unused))) { struct pollfd ufds[MAX_FDS]; char buf[BUF_SIZE]; @@ -254,10 +257,10 @@ void test_ppoll_big(FILE *validation_output_file __attribute__((unused))) PERROR("dup"); } ufds[i].fd = fds[i]; - ufds[i].events = POLLIN|POLLPRI; + ufds[i].events = POLLIN | POLLPRI; } - ret = ppoll(ufds, MAX_FDS, NULL, NULL); + ret = ppoll(ufds, MAX_FDS, nullptr, nullptr); if (ret < 0) { PERROR("ppoll"); @@ -278,8 +281,7 @@ void test_ppoll_big(FILE *validation_output_file __attribute__((unused))) return; } -static -void test_epoll(FILE *validation_output_file) +static void test_epoll(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -291,8 +293,7 @@ void test_epoll(FILE *validation_output_file) goto end; } - ret = fprintf(validation_output_file, - ", \"epoll_wait_fd\": %i", epollfd); + ret = fprintf(validation_output_file, ", \"epoll_wait_fd\": %i", epollfd); if (ret < 0) { PERROR("[epoll] Failed to write test validation output"); goto error; @@ -330,8 +331,7 @@ end: return; } -static -void test_epoll_pwait(FILE *validation_output_file) +static void test_epoll_pwait(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -343,8 +343,7 @@ void test_epoll_pwait(FILE *validation_output_file) goto end; } - ret = fprintf(validation_output_file, - ", \"epoll_pwait_fd\": %i", epollfd); + ret = fprintf(validation_output_file, ", \"epoll_pwait_fd\": %i", epollfd); if (ret < 0) { PERROR("[epoll_pwait] Failed to write test validation output"); goto error; @@ -359,9 +358,9 @@ void test_epoll_pwait(FILE *validation_output_file) } if (timeout > 0) { - ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL); + ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, nullptr); } else { - ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL); + ret = epoll_pwait(epollfd, &epoll_event, 1, -1, nullptr); } if (ret == 1) { @@ -382,8 +381,7 @@ end: return; } -static -void run_working_cases(FILE *validation_output_file) +static void run_working_cases(FILE *validation_output_file) { int ret; int pipe_fds[2]; @@ -442,16 +440,14 @@ end: * segfault (eventually with a "*** stack smashing detected ***" message). * The event should contain an array of 100 FDs filled with garbage. */ -static -void ppoll_fds_buffer_overflow( - FILE *validation_output_file __attribute__((unused))) +static void ppoll_fds_buffer_overflow(FILE *validation_output_file __attribute__((unused))) { struct pollfd ufds[NB_FD]; char buf[BUF_SIZE]; int ret; ufds[0].fd = wait_fd; - ufds[0].events = POLLIN|POLLPRI; + ufds[0].events = POLLIN | POLLPRI; ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL); @@ -470,15 +466,14 @@ void ppoll_fds_buffer_overflow( * cleanly fail with a "Invalid argument". * The event should contain an empty array of FDs and overflow = 1. */ -static -void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused))) +static void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused))) { struct pollfd ufds[NB_FD]; char buf[BUF_SIZE]; int ret; ufds[0].fd = wait_fd; - ufds[0].events = POLLIN|POLLPRI; + ufds[0].events = POLLIN | POLLPRI; ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL); if (ret < 0) { @@ -495,8 +490,7 @@ void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused))) * Pass an invalid file descriptor to pselect6(). The syscall should return * -EBADF. The recorded event should contain a "ret = -EBADF (-9)". */ -static -void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused))) +static void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused))) { fd_set rfds; int ret; @@ -538,9 +532,7 @@ error: * Invalid pointer as writefds, should output a ppoll event * with 0 FDs. */ -static -void pselect_invalid_pointer( - FILE *validation_output_file __attribute__((unused))) +static void pselect_invalid_pointer(FILE *validation_output_file __attribute__((unused))) { fd_set rfds; int ret; @@ -550,8 +542,7 @@ void pselect_invalid_pointer( FD_ZERO(&rfds); FD_SET(wait_fd, &rfds); - ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL, - NULL); + ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL); if (ret == -1) { /* Expected error. */ } else if (ret) { @@ -566,8 +557,7 @@ void pselect_invalid_pointer( * Pass an invalid pointer to epoll_pwait, should fail with * "Bad address", the event returns 0 FDs. */ -static -void epoll_pwait_invalid_pointer(FILE *validation_output_file) +static void epoll_pwait_invalid_pointer(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -580,9 +570,8 @@ void epoll_pwait_invalid_pointer(FILE *validation_output_file) goto end; } - ret = fprintf(validation_output_file, - "{ \"epollfd\": %i, \"pid\": %i }", epollfd, - getpid()); + ret = fprintf( + validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid()); if (ret < 0) { PERROR("[epoll_pwait] Failed to write test validation output"); goto error; @@ -596,8 +585,7 @@ void epoll_pwait_invalid_pointer(FILE *validation_output_file) goto error; } - ret = syscall(SYS_epoll_pwait, epollfd, - (struct epoll_event *) invalid, 1, -1, NULL); + ret = syscall(SYS_epoll_pwait, epollfd, (struct epoll_event *) invalid, 1, -1, NULL); if (ret == 1) { ret = read(wait_fd, buf, BUF_SIZE); @@ -621,8 +609,7 @@ end: * Set maxevents to INT_MAX, should output "Invalid argument" * The event should return an empty array. */ -static -void epoll_pwait_int_max(FILE *validation_output_file) +static void epoll_pwait_int_max(FILE *validation_output_file) { int ret, epollfd; char buf[BUF_SIZE]; @@ -634,9 +621,8 @@ void epoll_pwait_int_max(FILE *validation_output_file) goto end; } - ret = fprintf(validation_output_file, - "{ \"epollfd\": %i, \"pid\": %i }", epollfd, - getpid()); + ret = fprintf( + validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid()); if (ret < 0) { PERROR("[epoll_pwait] Failed to write test validation output"); goto error; @@ -650,8 +636,7 @@ void epoll_pwait_int_max(FILE *validation_output_file) goto error; } - ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, - NULL); + ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, NULL); if (ret == 1) { ret = read(wait_fd, buf, BUF_SIZE); @@ -671,22 +656,19 @@ end: return; } -static -void *ppoll_writer(void *arg) +static void *ppoll_writer(void *arg) { struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg; while (!stop_thread) { - memset(data->ufds, data->value, - MAX_FDS * sizeof(struct pollfd)); + memset(data->ufds, data->value, MAX_FDS * sizeof(struct pollfd)); usleep(100); } - return NULL; + return nullptr; } -static -void do_ppoll(int *fds, struct pollfd *ufds) +static void do_ppoll(int *fds, struct pollfd *ufds) { int i, ret; struct timespec ts; @@ -697,10 +679,10 @@ void do_ppoll(int *fds, struct pollfd *ufds) for (i = 0; i < MAX_FDS; i++) { ufds[i].fd = fds[i]; - ufds[i].events = POLLIN|POLLPRI; + ufds[i].events = POLLIN | POLLPRI; } - ret = ppoll(ufds, MAX_FDS, &ts, NULL); + ret = ppoll(ufds, MAX_FDS, &ts, nullptr); if (ret < 0) { PERROR("ppoll"); @@ -712,8 +694,7 @@ void do_ppoll(int *fds, struct pollfd *ufds) } } -static -void stress_ppoll(int *fds, int value) +static void stress_ppoll(int *fds, int value) { pthread_t writer; int iter, ret; @@ -724,7 +705,7 @@ void stress_ppoll(int *fds, int value) thread_data.value = value; stop_thread = 0; - ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data); + ret = pthread_create(&writer, nullptr, &ppoll_writer, (void *) &thread_data); if (ret != 0) { fprintf(stderr, "[error] pthread_create\n"); goto end; @@ -733,7 +714,7 @@ void stress_ppoll(int *fds, int value) do_ppoll(fds, ufds); } stop_thread = 1; - ret = pthread_join(writer, NULL); + ret = pthread_join(writer, nullptr); if (ret) { fprintf(stderr, "[error] pthread_join\n"); goto end; @@ -754,9 +735,7 @@ end: * * ppoll should work as expected and the trace should be readable at the end. */ -static -void ppoll_concurrent_write( - FILE *validation_output_file __attribute__((unused))) +static void ppoll_concurrent_write(FILE *validation_output_file __attribute__((unused))) { int i, ret, fds[MAX_FDS]; @@ -781,17 +760,16 @@ void ppoll_concurrent_write( return; } -static -void *epoll_pwait_writer(void *addr) +static void *epoll_pwait_writer(void *addr) { - srand(time(NULL)); + srand(time(nullptr)); while (!stop_thread) { usleep(rand() % 30); munmap(addr, MAX_FDS * sizeof(struct epoll_event)); } - return NULL; + return nullptr; } /* @@ -799,8 +777,7 @@ void *epoll_pwait_writer(void *addr) * buffer allocated for the returned data. This should randomly segfault. * The trace should be readable and no kernel OOPS should occur. */ -static -void epoll_pwait_concurrent_munmap(FILE *validation_output_file) +static void epoll_pwait_concurrent_munmap(FILE *validation_output_file) { int ret, epollfd, i, fds[MAX_FDS]; char buf[BUF_SIZE]; @@ -816,18 +793,19 @@ void epoll_pwait_concurrent_munmap(FILE *validation_output_file) goto end; } - ret = fprintf(validation_output_file, - "{ \"epollfd\": %i, \"pid\": %i }", epollfd, - getpid()); + ret = fprintf( + validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid()); if (ret < 0) { PERROR("[epoll_pwait] Failed to write test validation output"); goto error; } - epoll_event = (struct epoll_event *) mmap(NULL, - MAX_FDS * sizeof(struct epoll_event), - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, - 0); + epoll_event = (struct epoll_event *) mmap(nullptr, + MAX_FDS * sizeof(struct epoll_event), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0); if (epoll_event == MAP_FAILED) { PERROR("mmap"); goto error; @@ -847,14 +825,13 @@ void epoll_pwait_concurrent_munmap(FILE *validation_output_file) } } stop_thread = 0; - ret = pthread_create(&writer, NULL, &epoll_pwait_writer, - (void *) epoll_event); + ret = pthread_create(&writer, nullptr, &epoll_pwait_writer, (void *) epoll_event); if (ret != 0) { fprintf(stderr, "[error] pthread_create\n"); goto error_unmap; } - ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL); + ret = epoll_pwait(epollfd, epoll_event, 1, 1, nullptr); if (ret == 1) { ret = read(wait_fd, buf, BUF_SIZE); @@ -866,7 +843,7 @@ void epoll_pwait_concurrent_munmap(FILE *validation_output_file) } stop_thread = 1; - ret = pthread_join(writer, NULL); + ret = pthread_join(writer, nullptr); if (ret) { fprintf(stderr, "[error] pthread_join\n"); goto error_unmap; @@ -893,31 +870,38 @@ end: return; } -static -void print_list(void) +static void print_list() { fprintf(stderr, "Test list (-t X):\n"); - fprintf(stderr, "\t1: Working cases for select, pselect6, poll, ppoll " - "and epoll, waiting for input\n"); - fprintf(stderr, "\t2: Timeout cases (1ms) for select, pselect6, poll, " - "ppoll and epoll\n"); + fprintf(stderr, + "\t1: Working cases for select, pselect6, poll, ppoll " + "and epoll, waiting for input\n"); + fprintf(stderr, + "\t2: Timeout cases (1ms) for select, pselect6, poll, " + "ppoll and epoll\n"); fprintf(stderr, "\t3: pselect with an invalid fd\n"); fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS); - fprintf(stderr, "\t5: ppoll buffer overflow, should segfault, waits " - "for input\n"); - fprintf(stderr, "\t6: pselect with an invalid pointer, waits for " - "input\n"); + fprintf(stderr, + "\t5: ppoll buffer overflow, should segfault, waits " + "for input\n"); + fprintf(stderr, + "\t6: pselect with an invalid pointer, waits for " + "input\n"); fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n"); - fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for " - "input\n"); - fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, " - "waits for input\n"); - fprintf(stderr, "\t10: ppoll with concurrent updates of the structure " - "from user-space, stress test (3000 iterations), " - "waits for input + timeout 1ms\n"); - fprintf(stderr, "\t11: epoll_pwait with concurrent munmap of the buffer " - "from user-space, should randomly segfault, run " - "multiple times, waits for input + timeout 1ms\n"); + fprintf(stderr, + "\t8: epoll_pwait with an invalid pointer, waits for " + "input\n"); + fprintf(stderr, + "\t9: epoll_pwait with maxevents set to INT_MAX, " + "waits for input\n"); + fprintf(stderr, + "\t10: ppoll with concurrent updates of the structure " + "from user-space, stress test (3000 iterations), " + "waits for input + timeout 1ms\n"); + fprintf(stderr, + "\t11: epoll_pwait with concurrent munmap of the buffer " + "from user-space, should randomly segfault, run " + "multiple times, waits for input + timeout 1ms\n"); } int main(int argc, const char **argv) @@ -925,21 +909,23 @@ int main(int argc, const char **argv) int c, ret, test = -1; poptContext optCon; struct rlimit open_lim; - FILE *test_validation_output_file = NULL; - const char *test_validation_output_file_path = NULL; + FILE *test_validation_output_file = nullptr; + const char *test_validation_output_file_path = nullptr; struct poptOption optionsTable[] = { - { "test", 't', POPT_ARG_INT, &test, 0, - "Test to run", NULL }, - { "list", 'l', 0, 0, 'l', - "List of tests (-t X)", NULL }, - { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0, - "Test case output", NULL }, - POPT_AUTOHELP - { NULL, 0, 0, NULL, 0 } + { "test", 't', POPT_ARG_INT, &test, 0, "Test to run", nullptr }, + { "list", 'l', 0, nullptr, 'l', "List of tests (-t X)", nullptr }, + { "validation-file", + 'o', + POPT_ARG_STRING, + &test_validation_output_file_path, + 0, + "Test case output", + nullptr }, + POPT_AUTOHELP{ nullptr, 0, 0, nullptr, 0, nullptr, nullptr } }; const struct test_case *test_case; - optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); + optCon = poptGetContext(nullptr, argc, argv, optionsTable, 0); if (argc < 2) { poptPrintUsage(optCon, stderr, 0); @@ -966,7 +952,7 @@ int main(int argc, const char **argv) test_validation_output_file = fopen(test_validation_output_file_path, "w+"); if (!test_validation_output_file) { PERROR("Failed to create test validation output file at '%s'", - test_validation_output_file_path); + test_validation_output_file_path); ret = -1; goto end; } @@ -985,7 +971,7 @@ int main(int argc, const char **argv) * for the validation, disabling the buffering on the validation file * works. */ - setbuf(test_validation_output_file, NULL); + setbuf(test_validation_output_file, nullptr); wait_fd = STDIN_FILENO; /* Test case id is 1-based. */