Fix: tests: CFLAGS to CXXFLAGS when converting to C++
[lttng-tools.git] / tests / regression / kernel / select_poll_epoll.cpp
CommitLineData
9d16b343
MJ
1/*
2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
fbf606d7
MJ
8/*
9 * This test voluntarily does buffer overflows and stack overruns, disable
10 * source fortification.
11 */
12#ifdef _FORTIFY_SOURCE
13#undef _FORTIFY_SOURCE
14#endif
15
c9e313bc
SM
16#include <fcntl.h>
17#include <limits.h>
a0b1f42c 18#include <poll.h>
c9e313bc
SM
19#include <popt.h>
20#include <pthread.h>
a0b1f42c 21#include <signal.h>
c9e313bc
SM
22#include <stddef.h>
23#include <stdio.h>
a0b1f42c
JD
24#include <stdlib.h>
25#include <string.h>
a0b1f42c 26#include <sys/epoll.h>
a0b1f42c 27#include <sys/mman.h>
c9e313bc
SM
28#include <sys/resource.h>
29#include <sys/select.h>
30#include <sys/stat.h>
31#include <sys/syscall.h>
32#include <sys/time.h>
33#include <sys/types.h>
34#include <unistd.h>
35
36#include <common/compat/time.hpp>
37#include <common/error.hpp>
a0b1f42c
JD
38
39#define BUF_SIZE 256
40#define NB_FD 1
41#define MAX_FDS 2047
42#define NR_ITER 1000 /* for stress-tests */
43
44#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
45#define BIG_SELECT_FD 1022
46
47#define MSEC_PER_USEC 1000
48#define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
49
50static int timeout; /* seconds, -1 to disable */
44a411a6 51static volatile int stop_thread;
a0b1f42c
JD
52static int wait_fd;
53
d40c2620
JG
54/* Used by logging utils. */
55int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
56
57static void run_working_cases(FILE *validation_output_file);
58static void pselect_invalid_fd(FILE *validation_output_file);
59static void test_ppoll_big(FILE *validation_output_file);
60static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
61static void pselect_invalid_pointer(FILE *validation_output_file);
62static void ppoll_fds_ulong_max(FILE *validation_output_file);
63static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
64static void epoll_pwait_int_max(FILE *validation_output_file);
65static void ppoll_concurrent_write(FILE *validation_output_file);
66static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
67
68typedef void (*test_case_cb)(FILE *output_file);
69
f1494934
JG
70namespace {
71const struct test_case {
d40c2620
JG
72 test_case_cb run;
73 bool produces_validation_info;
74 int timeout;
75} test_cases [] =
76{
77 { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 },
78 { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 },
1c9a0b0e
MJ
79 { .run = pselect_invalid_fd, .produces_validation_info = false, .timeout = 0 },
80 { .run = test_ppoll_big, .produces_validation_info = false, .timeout = 0 },
81 { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false, .timeout = 0 },
82 { .run = pselect_invalid_pointer, .produces_validation_info = false, .timeout = 0 },
83 { .run = ppoll_fds_ulong_max, .produces_validation_info = false, .timeout = 0 },
84 { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true, .timeout = 0 },
85 { .run = epoll_pwait_int_max, .produces_validation_info = true, .timeout = 0 },
86 { .run = ppoll_concurrent_write, .produces_validation_info = false, .timeout = 0 },
87 { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true, .timeout = 0 },
d40c2620
JG
88};
89
a0b1f42c
JD
90struct ppoll_thread_data {
91 struct pollfd *ufds;
92 int value;
93};
f1494934 94} /* namespace */
a0b1f42c 95
f12eb9c1 96static
a0b1f42c
JD
97void test_select_big(void)
98{
99 fd_set rfds, wfds, exfds;
100 struct timeval tv;
101 int ret;
102 int fd2;
103 char buf[BUF_SIZE];
104
105 FD_ZERO(&rfds);
106 FD_ZERO(&wfds);
107 FD_ZERO(&exfds);
108
109 fd2 = dup2(wait_fd, BIG_SELECT_FD);
110 if (fd2 < 0) {
d40c2620 111 PERROR("dup2");
a0b1f42c
JD
112 goto end;
113 }
114 FD_SET(fd2, &rfds);
115
116 tv.tv_sec = 0;
117 tv.tv_usec = timeout * MSEC_PER_USEC;
118
119 if (timeout > 0) {
120 ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv);
121 } else {
122 ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
123 }
124
125 if (ret == -1) {
d40c2620 126 PERROR("select()");
a0b1f42c 127 } else if (ret) {
a0b1f42c
JD
128 ret = read(wait_fd, buf, BUF_SIZE);
129 if (ret < 0) {
d40c2620 130 PERROR("[select] read");
a0b1f42c 131 }
a0b1f42c
JD
132 }
133
134 ret = close(BIG_SELECT_FD);
135 if (ret) {
d40c2620 136 PERROR("close");
a0b1f42c
JD
137 }
138
139end:
140 return;
141}
142
f12eb9c1 143static
a0b1f42c
JD
144void test_pselect(void)
145{
146 fd_set rfds;
147 struct timespec tv;
148 int ret;
149 char buf[BUF_SIZE];
150
151 FD_ZERO(&rfds);
152 FD_SET(wait_fd, &rfds);
153
154 tv.tv_sec = 0;
155 tv.tv_nsec = timeout * MSEC_PER_NSEC;
156
157 if (timeout > 0) {
158 ret = pselect(1, &rfds, NULL, NULL, &tv, NULL);
159 } else {
160 ret = pselect(1, &rfds, NULL, NULL, NULL, NULL);
161 }
162
163 if (ret == -1) {
d40c2620 164 PERROR("pselect()");
a0b1f42c 165 } else if (ret) {
a0b1f42c
JD
166 ret = read(wait_fd, buf, BUF_SIZE);
167 if (ret < 0) {
d40c2620 168 PERROR("[pselect] read");
a0b1f42c 169 }
a0b1f42c 170 }
a0b1f42c
JD
171}
172
f12eb9c1 173static
a0b1f42c
JD
174void test_select(void)
175{
176 fd_set rfds;
177 struct timeval tv;
178 int ret;
179 char buf[BUF_SIZE];
180
181 FD_ZERO(&rfds);
182 FD_SET(wait_fd, &rfds);
183
184 tv.tv_sec = 0;
185 tv.tv_usec = timeout * MSEC_PER_USEC;
186
187 if (timeout > 0) {
188 ret = select(1, &rfds, NULL, NULL, &tv);
189 } else {
190 ret = select(1, &rfds, NULL, NULL, NULL);
191 }
192
193 if (ret == -1) {
d40c2620 194 PERROR("select()");
a0b1f42c 195 } else if (ret) {
a0b1f42c
JD
196 ret = read(wait_fd, buf, BUF_SIZE);
197 if (ret < 0) {
d40c2620 198 PERROR("[select] read");
a0b1f42c 199 }
a0b1f42c 200 }
a0b1f42c
JD
201}
202
f12eb9c1 203static
a0b1f42c
JD
204void test_poll(void)
205{
206 struct pollfd ufds[NB_FD];
207 char buf[BUF_SIZE];
208 int ret;
209
210 ufds[0].fd = wait_fd;
211 ufds[0].events = POLLIN|POLLPRI;
212
213 ret = poll(ufds, 1, timeout);
214
215 if (ret < 0) {
d40c2620 216 PERROR("poll");
a0b1f42c 217 } else if (ret > 0) {
a0b1f42c
JD
218 ret = read(wait_fd, buf, BUF_SIZE);
219 if (ret < 0) {
d40c2620 220 PERROR("[poll] read");
a0b1f42c 221 }
a0b1f42c
JD
222 }
223}
224
f12eb9c1 225static
a0b1f42c
JD
226void test_ppoll(void)
227{
228 struct pollfd ufds[NB_FD];
229 char buf[BUF_SIZE];
230 int ret;
231 struct timespec ts;
232
233 ufds[0].fd = wait_fd;
234 ufds[0].events = POLLIN|POLLPRI;
235
236 if (timeout > 0) {
237 ts.tv_sec = 0;
238 ts.tv_nsec = timeout * MSEC_PER_NSEC;
239 ret = ppoll(ufds, 1, &ts, NULL);
240 } else {
241 ret = ppoll(ufds, 1, NULL, NULL);
242 }
243
244
245 if (ret < 0) {
d40c2620 246 PERROR("ppoll");
a0b1f42c 247 } else if (ret > 0) {
a0b1f42c
JD
248 ret = read(wait_fd, buf, BUF_SIZE);
249 if (ret < 0) {
d40c2620 250 PERROR("[ppoll] read");
a0b1f42c 251 }
a0b1f42c
JD
252 }
253}
254
f12eb9c1 255static
f46376a1 256void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
257{
258 struct pollfd ufds[MAX_FDS];
259 char buf[BUF_SIZE];
260 int ret, i, fds[MAX_FDS];
261
262 for (i = 0; i < MAX_FDS; i++) {
263 fds[i] = dup(wait_fd);
264 if (fds[i] < 0) {
d40c2620 265 PERROR("dup");
a0b1f42c
JD
266 }
267 ufds[i].fd = fds[i];
268 ufds[i].events = POLLIN|POLLPRI;
269 }
270
271 ret = ppoll(ufds, MAX_FDS, NULL, NULL);
272
273 if (ret < 0) {
d40c2620 274 PERROR("ppoll");
a0b1f42c 275 } else if (ret > 0) {
a0b1f42c
JD
276 ret = read(wait_fd, buf, BUF_SIZE);
277 if (ret < 0) {
d40c2620 278 PERROR("[ppoll] read");
a0b1f42c 279 }
a0b1f42c
JD
280 }
281
282 for (i = 0; i < MAX_FDS; i++) {
283 ret = close(fds[i]);
284 if (ret != 0) {
d40c2620 285 PERROR("close");
a0b1f42c
JD
286 }
287 }
288
289 return;
290}
291
f12eb9c1 292static
d40c2620 293void test_epoll(FILE *validation_output_file)
a0b1f42c
JD
294{
295 int ret, epollfd;
296 char buf[BUF_SIZE];
297 struct epoll_event epoll_event;
298
299 epollfd = epoll_create(NB_FD);
300 if (epollfd < 0) {
d40c2620 301 PERROR("[epoll] create");
a0b1f42c
JD
302 goto end;
303 }
304
d40c2620
JG
305 ret = fprintf(validation_output_file,
306 ", \"epoll_wait_fd\": %i", epollfd);
307 if (ret < 0) {
308 PERROR("[epoll] Failed to write test validation output");
309 goto error;
310 }
311
a0b1f42c
JD
312 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
313 epoll_event.data.fd = wait_fd;
314 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
315 if (ret < 0) {
d40c2620 316 PERROR("[epoll] add");
5305e823 317 goto error;
a0b1f42c
JD
318 }
319
320 if (timeout > 0) {
321 ret = epoll_wait(epollfd, &epoll_event, 1, timeout);
322 } else {
323 ret = epoll_wait(epollfd, &epoll_event, 1, -1);
324 }
325
326 if (ret == 1) {
a0b1f42c
JD
327 ret = read(wait_fd, buf, BUF_SIZE);
328 if (ret < 0) {
d40c2620 329 PERROR("[epoll] read");
a0b1f42c 330 }
d40c2620
JG
331 } else if (ret != 0) {
332 PERROR("epoll_wait");
a0b1f42c
JD
333 }
334
5305e823 335error:
6d52f14d
FD
336 ret = close(epollfd);
337 if (ret) {
d40c2620 338 PERROR("close");
6d52f14d 339 }
a0b1f42c
JD
340end:
341 return;
342}
343
f12eb9c1 344static
d40c2620 345void test_epoll_pwait(FILE *validation_output_file)
a0b1f42c
JD
346{
347 int ret, epollfd;
348 char buf[BUF_SIZE];
349 struct epoll_event epoll_event;
350
351 epollfd = epoll_create(NB_FD);
352 if (epollfd < 0) {
d40c2620 353 PERROR("[epoll_pwait] create");
a0b1f42c
JD
354 goto end;
355 }
356
d40c2620
JG
357 ret = fprintf(validation_output_file,
358 ", \"epoll_pwait_fd\": %i", epollfd);
359 if (ret < 0) {
360 PERROR("[epoll_pwait] Failed to write test validation output");
361 goto error;
362 }
363
a0b1f42c
JD
364 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
365 epoll_event.data.fd = wait_fd;
366 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
367 if (ret < 0) {
d40c2620 368 PERROR("[epoll_pwait] add");
5305e823 369 goto error;
a0b1f42c
JD
370 }
371
372 if (timeout > 0) {
373 ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
374 } else {
375 ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL);
376 }
377
378 if (ret == 1) {
a0b1f42c
JD
379 ret = read(wait_fd, buf, BUF_SIZE);
380 if (ret < 0) {
d40c2620 381 PERROR("[epoll_pwait] read");
a0b1f42c 382 }
d40c2620
JG
383 } else if (ret != 0) {
384 PERROR("epoll_pwait");
a0b1f42c
JD
385 }
386
5305e823 387error:
6d52f14d
FD
388 ret = close(epollfd);
389 if (ret) {
d40c2620 390 PERROR("close");
6d52f14d 391 }
a0b1f42c
JD
392end:
393 return;
394}
395
f12eb9c1 396static
d40c2620 397void run_working_cases(FILE *validation_output_file)
a0b1f42c
JD
398{
399 int ret;
400 int pipe_fds[2];
401
402 if (timeout > 0) {
403 /*
404 * We need an input pipe for some cases and stdin might
405 * have random data, so we create a dummy pipe for this
406 * test to make sure we are running under clean conditions.
407 */
408 ret = pipe(pipe_fds);
409 if (ret != 0) {
d40c2620 410 PERROR("pipe");
a0b1f42c
JD
411 goto end;
412 }
413 wait_fd = pipe_fds[0];
414 }
415 test_select();
416 test_pselect();
417 test_select_big();
418 test_poll();
419 test_ppoll();
d40c2620
JG
420
421 ret = fprintf(validation_output_file, "{ \"pid\": %i", getpid());
422 if (ret < 0) {
423 PERROR("Failed to write pid to test validation file");
424 goto end;
425 }
426
427 test_epoll(validation_output_file);
428 test_epoll_pwait(validation_output_file);
a0b1f42c
JD
429
430 if (timeout > 0) {
431 ret = close(pipe_fds[0]);
432 if (ret) {
d40c2620 433 PERROR("close");
a0b1f42c
JD
434 }
435 ret = close(pipe_fds[1]);
436 if (ret) {
d40c2620 437 PERROR("close");
a0b1f42c
JD
438 }
439 }
440
d40c2620
JG
441 ret = fputs(" }", validation_output_file);
442 if (ret < 0) {
443 PERROR("Failed to close JSON dictionary in test validation file");
444 goto end;
445 }
446
a0b1f42c
JD
447end:
448 return;
449}
450
451/*
452 * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
453 * segfault (eventually with a "*** stack smashing detected ***" message).
454 * The event should contain an array of 100 FDs filled with garbage.
455 */
f12eb9c1 456static
f46376a1
MJ
457void ppoll_fds_buffer_overflow(
458 FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
459{
460 struct pollfd ufds[NB_FD];
461 char buf[BUF_SIZE];
462 int ret;
463
464 ufds[0].fd = wait_fd;
465 ufds[0].events = POLLIN|POLLPRI;
466
467 ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
468
469 if (ret < 0) {
d40c2620 470 PERROR("ppoll");
a0b1f42c 471 } else if (ret > 0) {
a0b1f42c
JD
472 ret = read(wait_fd, buf, BUF_SIZE);
473 if (ret < 0) {
d40c2620 474 PERROR("[ppoll] read");
a0b1f42c 475 }
a0b1f42c 476 }
a0b1f42c
JD
477}
478
479/*
480 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
481 * cleanly fail with a "Invalid argument".
482 * The event should contain an empty array of FDs and overflow = 1.
483 */
f12eb9c1 484static
f46376a1 485void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
486{
487 struct pollfd ufds[NB_FD];
488 char buf[BUF_SIZE];
489 int ret;
490
491 ufds[0].fd = wait_fd;
492 ufds[0].events = POLLIN|POLLPRI;
493
494 ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
a0b1f42c 495 if (ret < 0) {
d40c2620 496 /* Expected error. */
a0b1f42c 497 } else if (ret > 0) {
a0b1f42c
JD
498 ret = read(wait_fd, buf, BUF_SIZE);
499 if (ret < 0) {
d40c2620 500 PERROR("[ppoll] read");
a0b1f42c 501 }
a0b1f42c 502 }
a0b1f42c
JD
503}
504
505/*
8b3b99e2
FD
506 * Pass an invalid file descriptor to pselect6(). The syscall should return
507 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
a0b1f42c 508 */
f12eb9c1 509static
f46376a1 510void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
a0b1f42c 511{
8b3b99e2 512 fd_set rfds;
a0b1f42c 513 int ret;
8b3b99e2 514 int fd;
a0b1f42c
JD
515 char buf[BUF_SIZE];
516
517 /*
8b3b99e2 518 * Open a file, close it and use the closed FD in the pselect6 call.
a0b1f42c 519 */
8b3b99e2
FD
520 fd = open("/dev/null", O_RDONLY);
521 if (fd == -1) {
d40c2620 522 PERROR("open");
8b3b99e2
FD
523 goto error;
524 }
525
526 ret = close(fd);
527 if (ret == -1) {
d40c2620 528 PERROR("close");
8b3b99e2 529 goto error;
a0b1f42c 530 }
e593ee02 531
8b3b99e2
FD
532 FD_ZERO(&rfds);
533 FD_SET(fd, &rfds);
a0b1f42c 534
8b3b99e2 535 ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
a0b1f42c 536 if (ret == -1) {
d40c2620 537 /* Expected error. */
a0b1f42c 538 } else if (ret) {
a0b1f42c
JD
539 ret = read(wait_fd, buf, BUF_SIZE);
540 if (ret < 0) {
d40c2620 541 PERROR("[pselect] read");
a0b1f42c 542 }
a0b1f42c 543 }
8b3b99e2
FD
544error:
545 return;
a0b1f42c
JD
546}
547
548/*
549 * Invalid pointer as writefds, should output a ppoll event
550 * with 0 FDs.
551 */
f12eb9c1 552static
f46376a1
MJ
553void pselect_invalid_pointer(
554 FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
555{
556 fd_set rfds;
557 int ret;
558 char buf[BUF_SIZE];
559 void *invalid = (void *) 0x42;
560
561 FD_ZERO(&rfds);
562 FD_SET(wait_fd, &rfds);
563
564 ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL,
565 NULL);
a0b1f42c 566 if (ret == -1) {
d40c2620 567 /* Expected error. */
a0b1f42c 568 } else if (ret) {
a0b1f42c
JD
569 ret = read(wait_fd, buf, BUF_SIZE);
570 if (ret < 0) {
d40c2620 571 PERROR("[pselect] read");
a0b1f42c 572 }
a0b1f42c 573 }
a0b1f42c
JD
574}
575
576/*
577 * Pass an invalid pointer to epoll_pwait, should fail with
578 * "Bad address", the event returns 0 FDs.
579 */
f12eb9c1 580static
d40c2620 581void epoll_pwait_invalid_pointer(FILE *validation_output_file)
a0b1f42c
JD
582{
583 int ret, epollfd;
584 char buf[BUF_SIZE];
585 struct epoll_event epoll_event;
586 void *invalid = (void *) 0x42;
587
588 epollfd = epoll_create(NB_FD);
589 if (epollfd < 0) {
d40c2620 590 PERROR("[epoll_pwait] create");
a0b1f42c
JD
591 goto end;
592 }
593
d40c2620
JG
594 ret = fprintf(validation_output_file,
595 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
596 getpid());
597 if (ret < 0) {
598 PERROR("[epoll_pwait] Failed to write test validation output");
599 goto error;
600 }
601
a0b1f42c
JD
602 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
603 epoll_event.data.fd = wait_fd;
604 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
605 if (ret < 0) {
d40c2620 606 PERROR("[epoll_pwait] add");
5305e823 607 goto error;
a0b1f42c
JD
608 }
609
610 ret = syscall(SYS_epoll_pwait, epollfd,
611 (struct epoll_event *) invalid, 1, -1, NULL);
612
613 if (ret == 1) {
a0b1f42c
JD
614 ret = read(wait_fd, buf, BUF_SIZE);
615 if (ret < 0) {
d40c2620 616 PERROR("[epoll_pwait] read");
a0b1f42c 617 }
d40c2620
JG
618 } else if (ret != 0) {
619 /* Expected error. */
a0b1f42c
JD
620 }
621
5305e823 622error:
6d52f14d
FD
623 ret = close(epollfd);
624 if (ret) {
d40c2620 625 PERROR("close");
6d52f14d 626 }
a0b1f42c
JD
627end:
628 return;
629}
630
631/*
632 * Set maxevents to INT_MAX, should output "Invalid argument"
633 * The event should return an empty array.
634 */
f12eb9c1 635static
d40c2620 636void epoll_pwait_int_max(FILE *validation_output_file)
a0b1f42c
JD
637{
638 int ret, epollfd;
639 char buf[BUF_SIZE];
640 struct epoll_event epoll_event;
641
642 epollfd = epoll_create(NB_FD);
643 if (epollfd < 0) {
d40c2620 644 PERROR("[epoll_pwait] create");
a0b1f42c
JD
645 goto end;
646 }
647
d40c2620
JG
648 ret = fprintf(validation_output_file,
649 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
650 getpid());
651 if (ret < 0) {
652 PERROR("[epoll_pwait] Failed to write test validation output");
653 goto error;
654 }
655
a0b1f42c
JD
656 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
657 epoll_event.data.fd = wait_fd;
658 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
659 if (ret < 0) {
d40c2620 660 PERROR("[epoll_pwait] add");
5305e823 661 goto error;
a0b1f42c
JD
662 }
663
664 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1,
665 NULL);
666
667 if (ret == 1) {
a0b1f42c
JD
668 ret = read(wait_fd, buf, BUF_SIZE);
669 if (ret < 0) {
d40c2620 670 PERROR("[epoll_pwait] read");
a0b1f42c 671 }
d40c2620
JG
672 } else if (ret != 0) {
673 /* Expected error. */
a0b1f42c
JD
674 }
675
5305e823 676error:
6d52f14d
FD
677 ret = close(epollfd);
678 if (ret) {
d40c2620 679 PERROR("close");
6d52f14d 680 }
a0b1f42c
JD
681end:
682 return;
683}
684
f12eb9c1 685static
a0b1f42c
JD
686void *ppoll_writer(void *arg)
687{
688 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
689
690 while (!stop_thread) {
691 memset(data->ufds, data->value,
692 MAX_FDS * sizeof(struct pollfd));
693 usleep(100);
694 }
695
696 return NULL;
697}
698
f12eb9c1 699static
a0b1f42c
JD
700void do_ppoll(int *fds, struct pollfd *ufds)
701{
702 int i, ret;
703 struct timespec ts;
704 char buf[BUF_SIZE];
705
706 ts.tv_sec = 0;
707 ts.tv_nsec = 1 * MSEC_PER_NSEC;
708
709 for (i = 0; i < MAX_FDS; i++) {
710 ufds[i].fd = fds[i];
711 ufds[i].events = POLLIN|POLLPRI;
712 }
713
714 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
715
716 if (ret < 0) {
d40c2620 717 PERROR("ppoll");
a0b1f42c 718 } else if (ret > 0) {
a0b1f42c
JD
719 ret = read(wait_fd, buf, BUF_SIZE);
720 if (ret < 0) {
d40c2620 721 PERROR("[ppoll] read");
a0b1f42c 722 }
a0b1f42c
JD
723 }
724}
725
f12eb9c1 726static
a0b1f42c
JD
727void stress_ppoll(int *fds, int value)
728{
729 pthread_t writer;
730 int iter, ret;
731 struct ppoll_thread_data thread_data;
732 struct pollfd ufds[MAX_FDS];
733
734 thread_data.ufds = ufds;
735 thread_data.value = value;
736
737 stop_thread = 0;
738 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
739 if (ret != 0) {
740 fprintf(stderr, "[error] pthread_create\n");
741 goto end;
742 }
743 for (iter = 0; iter < NR_ITER; iter++) {
744 do_ppoll(fds, ufds);
745 }
746 stop_thread = 1;
9d558571
JG
747 ret = pthread_join(writer, NULL);
748 if (ret) {
749 fprintf(stderr, "[error] pthread_join\n");
750 goto end;
751 }
a0b1f42c
JD
752end:
753 return;
754}
755
756/*
757 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
758 * structure:
759 * - memset to 0
760 * - memset to 1
761 * - memset to INT_MAX
762 * Waits for input, but also set a timeout in case the input FD is overwritten
763 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
764 * resulting trace is big (20MB).
765 *
766 * ppoll should work as expected and the trace should be readable at the end.
767 */
f12eb9c1 768static
f46376a1
MJ
769void ppoll_concurrent_write(
770 FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
771{
772 int i, ret, fds[MAX_FDS];
773
774 for (i = 0; i < MAX_FDS; i++) {
775 fds[i] = dup(wait_fd);
776 if (fds[i] < 0) {
d40c2620 777 PERROR("dup");
a0b1f42c
JD
778 }
779 }
780
781 stress_ppoll(fds, 0);
782 stress_ppoll(fds, 1);
783 stress_ppoll(fds, INT_MAX);
784
785 for (i = 0; i < MAX_FDS; i++) {
786 ret = close(fds[i]);
787 if (ret != 0) {
d40c2620 788 PERROR("close");
a0b1f42c
JD
789 }
790 }
791
792 return;
793}
794
f12eb9c1 795static
a0b1f42c
JD
796void *epoll_pwait_writer(void *addr)
797{
798 srand(time(NULL));
799
800 while (!stop_thread) {
801 usleep(rand() % 30);
802 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
803 }
804
805 return NULL;
806}
807
808/*
809 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
810 * buffer allocated for the returned data. This should randomly segfault.
811 * The trace should be readable and no kernel OOPS should occur.
812 */
f12eb9c1 813static
d40c2620 814void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
a0b1f42c
JD
815{
816 int ret, epollfd, i, fds[MAX_FDS];
817 char buf[BUF_SIZE];
818 struct epoll_event *epoll_event;
a0b1f42c
JD
819 pthread_t writer;
820
7f6288c8
JG
821 for (i = 0; i < MAX_FDS; i++) {
822 fds[i] = -1;
823 }
a0b1f42c
JD
824 epollfd = epoll_create(MAX_FDS);
825 if (epollfd < 0) {
d40c2620 826 PERROR("[epoll_pwait] create");
a0b1f42c
JD
827 goto end;
828 }
829
d40c2620
JG
830 ret = fprintf(validation_output_file,
831 "{ \"epollfd\": %i, \"pid\": %i }", epollfd,
832 getpid());
833 if (ret < 0) {
834 PERROR("[epoll_pwait] Failed to write test validation output");
835 goto error;
836 }
837
838 epoll_event = (struct epoll_event *) mmap(NULL,
839 MAX_FDS * sizeof(struct epoll_event),
840 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1,
841 0);
a0b1f42c 842 if (epoll_event == MAP_FAILED) {
d40c2620 843 PERROR("mmap");
5305e823 844 goto error;
a0b1f42c
JD
845 }
846
847 for (i = 0; i < MAX_FDS; i++) {
848 fds[i] = dup(wait_fd);
849 if (fds[i] < 0) {
d40c2620 850 PERROR("dup");
a0b1f42c
JD
851 }
852 epoll_event[i].events = EPOLLIN | EPOLLPRI | EPOLLET;
853 epoll_event[i].data.fd = fds[i];
854 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], epoll_event);
855 if (ret < 0) {
d40c2620 856 PERROR("[epoll_pwait] add");
5305e823 857 goto error_unmap;
a0b1f42c
JD
858 }
859 }
860 stop_thread = 0;
d542c0ae
JG
861 ret = pthread_create(&writer, NULL, &epoll_pwait_writer,
862 (void *) epoll_event);
863 if (ret != 0) {
864 fprintf(stderr, "[error] pthread_create\n");
5305e823 865 goto error_unmap;
d542c0ae 866 }
a0b1f42c
JD
867
868 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
869
870 if (ret == 1) {
a0b1f42c
JD
871 ret = read(wait_fd, buf, BUF_SIZE);
872 if (ret < 0) {
d40c2620 873 PERROR("[epoll_pwait] read");
a0b1f42c 874 }
d40c2620
JG
875 } else if (ret != 0) {
876 /* Expected error. */
a0b1f42c
JD
877 }
878
879 stop_thread = 1;
9d558571
JG
880 ret = pthread_join(writer, NULL);
881 if (ret) {
882 fprintf(stderr, "[error] pthread_join\n");
5305e823 883 goto error_unmap;
9d558571 884 }
5305e823 885error_unmap:
a0b1f42c
JD
886 for (i = 0; i < MAX_FDS; i++) {
887 ret = close(fds[i]);
888 if (ret != 0) {
d40c2620 889 PERROR("close");
a0b1f42c
JD
890 }
891 }
892
36bc42d9 893 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
a0b1f42c 894 if (ret != 0) {
d40c2620 895 PERROR("munmap");
a0b1f42c
JD
896 }
897
5305e823 898error:
6d52f14d
FD
899 ret = close(epollfd);
900 if (ret) {
d40c2620 901 PERROR("close");
6d52f14d 902 }
a0b1f42c
JD
903end:
904 return;
905}
906
f12eb9c1 907static
a0b1f42c
JD
908void print_list(void)
909{
910 fprintf(stderr, "Test list (-t X):\n");
911 fprintf(stderr, "\t1: Working cases for select, pselect6, poll, ppoll "
912 "and epoll, waiting for input\n");
913 fprintf(stderr, "\t2: Timeout cases (1ms) for select, pselect6, poll, "
914 "ppoll and epoll\n");
8b3b99e2 915 fprintf(stderr, "\t3: pselect with an invalid fd\n");
a0b1f42c
JD
916 fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
917 fprintf(stderr, "\t5: ppoll buffer overflow, should segfault, waits "
918 "for input\n");
8b3b99e2 919 fprintf(stderr, "\t6: pselect with an invalid pointer, waits for "
a0b1f42c
JD
920 "input\n");
921 fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
8b3b99e2 922 fprintf(stderr, "\t8: epoll_pwait with an invalid pointer, waits for "
a0b1f42c
JD
923 "input\n");
924 fprintf(stderr, "\t9: epoll_pwait with maxevents set to INT_MAX, "
925 "waits for input\n");
926 fprintf(stderr, "\t10: ppoll with concurrent updates of the structure "
927 "from user-space, stress test (3000 iterations), "
928 "waits for input + timeout 1ms\n");
929 fprintf(stderr, "\t11: epoll_pwait with concurrent munmap of the buffer "
930 "from user-space, should randomly segfault, run "
931 "multiple times, waits for input + timeout 1ms\n");
932}
933
934int main(int argc, const char **argv)
935{
936 int c, ret, test = -1;
937 poptContext optCon;
938 struct rlimit open_lim;
d40c2620
JG
939 FILE *test_validation_output_file = NULL;
940 const char *test_validation_output_file_path = NULL;
a0b1f42c
JD
941 struct poptOption optionsTable[] = {
942 { "test", 't', POPT_ARG_INT, &test, 0,
943 "Test to run", NULL },
944 { "list", 'l', 0, 0, 'l',
945 "List of tests (-t X)", NULL },
d40c2620
JG
946 { "validation-file", 'o', POPT_ARG_STRING, &test_validation_output_file_path, 0,
947 "Test case output", NULL },
a0b1f42c 948 POPT_AUTOHELP
1c9a0b0e 949 { NULL, 0, 0, NULL, 0, NULL, NULL }
a0b1f42c 950 };
d40c2620 951 const struct test_case *test_case;
a0b1f42c
JD
952
953 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
954
955 if (argc < 2) {
956 poptPrintUsage(optCon, stderr, 0);
957 ret = -1;
958 goto end;
959 }
960
961 ret = 0;
962
963 while ((c = poptGetNextOpt(optCon)) >= 0) {
d40c2620 964 switch (c) {
a0b1f42c
JD
965 case 'l':
966 print_list();
967 goto end;
968 }
969 }
970
d40c2620
JG
971 if (!test_validation_output_file_path) {
972 fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n");
973 ret = -1;
974 goto end;
975 }
976
977 test_validation_output_file = fopen(test_validation_output_file_path, "w+");
978 if (!test_validation_output_file) {
979 PERROR("Failed to create test validation output file at '%s'",
980 test_validation_output_file_path);
981 ret = -1;
982 goto end;
983 }
984
a0b1f42c
JD
985 open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS;
986 open_lim.rlim_max = MAX_FDS + MIN_NR_FDS;
987
988 ret = setrlimit(RLIMIT_NOFILE, &open_lim);
989 if (ret < 0) {
d40c2620 990 PERROR("setrlimit");
a0b1f42c
JD
991 goto end;
992 }
993
994 /*
995 * Some tests might segfault, but we need the getpid() to be output
d40c2620
JG
996 * for the validation, disabling the buffering on the validation file
997 * works.
a0b1f42c 998 */
d40c2620 999 setbuf(test_validation_output_file, NULL);
a0b1f42c
JD
1000 wait_fd = STDIN_FILENO;
1001
d40c2620
JG
1002 /* Test case id is 1-based. */
1003 if (test < 1 || test > ARRAY_SIZE(test_cases)) {
a0b1f42c
JD
1004 poptPrintUsage(optCon, stderr, 0);
1005 ret = -1;
a0b1f42c
JD
1006 }
1007
d40c2620
JG
1008 test_case = &test_cases[test - 1];
1009
1010 timeout = test_case->timeout;
1011 if (!test_case->produces_validation_info) {
1012 /*
1013 * All test cases need to provide, at minimum, the pid of the
1014 * test application.
1015 */
1016 ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
1017 if (ret < 0) {
1018 PERROR("Failed to write application pid to test validation file");
1019 goto end;
1020 }
1021 }
1022
1023 test_case->run(test_validation_output_file);
1024
a0b1f42c 1025end:
d40c2620
JG
1026 if (test_validation_output_file) {
1027 const int close_ret = fclose(test_validation_output_file);
1028
1029 if (close_ret) {
1030 PERROR("Failed to close test output file");
1031 }
1032 }
a0b1f42c
JD
1033 poptFreeContext(optCon);
1034 return ret;
1035}
This page took 0.103016 seconds and 4 git commands to generate.