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