2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
9 * This test voluntarily does buffer overflows and stack overruns, disable
10 * source fortification.
12 #ifdef _FORTIFY_SOURCE
13 #undef _FORTIFY_SOURCE
16 #include <common/compat/time.hpp>
17 #include <common/error.hpp>
30 #include <sys/epoll.h>
32 #include <sys/resource.h>
33 #include <sys/select.h>
35 #include <sys/syscall.h>
37 #include <sys/types.h>
43 #define NR_ITER 1000 /* for stress-tests */
45 #define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
46 #define BIG_SELECT_FD 1022
48 #define MSEC_PER_USEC 1000
49 #define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
51 static int timeout
; /* seconds, -1 to disable */
52 static volatile int stop_thread
;
55 /* Used by logging utils. */
56 int lttng_opt_quiet
, lttng_opt_verbose
, lttng_opt_mi
;
58 static void run_working_cases(FILE *validation_output_file
);
59 static void test_ppoll_big(FILE *validation_output_file
);
60 static void pselect_invalid_pointer(FILE *validation_output_file
);
61 static void pselect_invalid_fd(FILE *validation_output_file
);
62 static void ppoll_fds_ulong_max(FILE *validation_output_file
);
63 static void ppoll_fds_buffer_overflow(FILE *validation_output_file
);
64 static void epoll_pwait_invalid_pointer(FILE *validation_output_file
);
65 static void epoll_pwait_int_max(FILE *validation_output_file
);
66 static void ppoll_concurrent_write(FILE *validation_output_file
);
67 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file
);
69 using test_case_cb
= void (*)(FILE *);
72 const struct test_case
{
74 bool produces_validation_info
;
77 const char *description
;
79 { .run
= run_working_cases
,
80 .produces_validation_info
= true,
82 .name
= "working_cases",
84 "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input" },
85 { .run
= run_working_cases
,
86 .produces_validation_info
= true,
88 .name
= "working_cases_timeout",
89 .description
= "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll" },
90 { .run
= test_ppoll_big
,
91 .produces_validation_info
= false,
94 .description
= "ppoll with " XSTR(MAX_FDS
) " FDs" },
95 { .run
= epoll_pwait_invalid_pointer
,
96 .produces_validation_info
= true,
98 .name
= "epoll_pwait_invalid_pointer",
99 .description
= "epoll_pwait with an invalid pointer, waits for input" },
100 { .run
= epoll_pwait_int_max
,
101 .produces_validation_info
= true,
103 .name
= "epoll_pwait_int_max",
104 .description
= "epoll_pwait with maxevents set to INT_MAX waits for input" },
105 { .run
= ppoll_concurrent_write
,
106 .produces_validation_info
= false,
108 .name
= "ppoll_concurrent_write",
110 "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations) waits for input + timeout 1ms" },
111 { .run
= epoll_pwait_concurrent_munmap
,
112 .produces_validation_info
= true,
114 .name
= "epoll_pwait_concurrent_munmap",
116 "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms" },
117 { .run
= pselect_invalid_pointer
,
118 .produces_validation_info
= false,
120 .name
= "pselect_invalid_pointer",
121 .description
= "pselect with an invalid pointer, waits for input" },
122 { .run
= pselect_invalid_fd
,
123 .produces_validation_info
= false,
125 .name
= "pselect_invalid_fd",
126 .description
= "pselect with an invalid fd" },
127 { .run
= ppoll_fds_ulong_max
,
128 .produces_validation_info
= false,
130 .name
= "ppoll_fds_ulong_max",
131 .description
= "ppoll with ulong_max fds, waits for input" },
132 { .run
= ppoll_fds_buffer_overflow
,
133 .produces_validation_info
= false,
135 .name
= "ppoll_fds_buffer_overflow",
136 .description
= "ppoll buffer overflow, should segfault, waits for input" },
139 struct ppoll_thread_data
{
145 static void test_select_big()
147 fd_set rfds
, wfds
, exfds
;
157 fd2
= dup2(wait_fd
, BIG_SELECT_FD
);
165 tv
.tv_usec
= timeout
* MSEC_PER_USEC
;
168 ret
= select(fd2
+ 1, &rfds
, &wfds
, &exfds
, &tv
);
170 ret
= select(fd2
+ 1, &rfds
, &wfds
, &exfds
, nullptr);
176 ret
= read(wait_fd
, buf
, BUF_SIZE
);
178 PERROR("[select] read");
182 ret
= close(BIG_SELECT_FD
);
191 static void test_pselect_generic(long int syscall_id
)
199 FD_SET(wait_fd
, &rfds
);
202 tv
.tv_nsec
= timeout
* MSEC_PER_NSEC
;
205 ret
= syscall(syscall_id
, 1, &rfds
, NULL
, NULL
, &tv
, NULL
);
207 ret
= syscall(syscall_id
, 1, &rfds
, NULL
, NULL
, NULL
, NULL
);
213 ret
= read(wait_fd
, buf
, BUF_SIZE
);
215 PERROR("[pselect] read");
220 static void test_pselect()
222 test_pselect_generic(SYS_pselect6
);
225 static void test_select()
233 FD_SET(wait_fd
, &rfds
);
236 tv
.tv_usec
= timeout
* MSEC_PER_USEC
;
239 ret
= select(1, &rfds
, nullptr, nullptr, &tv
);
241 ret
= select(1, &rfds
, nullptr, nullptr, nullptr);
247 ret
= read(wait_fd
, buf
, BUF_SIZE
);
249 PERROR("[select] read");
254 static void test_poll()
256 struct pollfd ufds
[NB_FD
];
260 ufds
[0].fd
= wait_fd
;
261 ufds
[0].events
= POLLIN
| POLLPRI
;
263 ret
= poll(ufds
, 1, timeout
);
267 } else if (ret
> 0) {
268 ret
= read(wait_fd
, buf
, BUF_SIZE
);
270 PERROR("[poll] read");
275 static void test_ppoll_generic(long int syscall_id
)
277 struct pollfd ufds
[NB_FD
];
282 ufds
[0].fd
= wait_fd
;
283 ufds
[0].events
= POLLIN
| POLLPRI
;
287 ts
.tv_nsec
= timeout
* MSEC_PER_NSEC
;
288 ret
= syscall(syscall_id
, ufds
, 1, &ts
, NULL
);
290 ret
= syscall(syscall_id
, ufds
, 1, NULL
, NULL
);
295 } else if (ret
> 0) {
296 ret
= read(wait_fd
, buf
, BUF_SIZE
);
298 PERROR("[ppoll] read");
303 static void test_ppoll()
305 test_ppoll_generic(SYS_ppoll
);
308 static void test_ppoll_big(FILE *validation_output_file
__attribute__((unused
)))
310 struct pollfd ufds
[MAX_FDS
];
312 int ret
, i
, fds
[MAX_FDS
];
314 for (i
= 0; i
< MAX_FDS
; i
++) {
315 fds
[i
] = dup(wait_fd
);
320 ufds
[i
].events
= POLLIN
| POLLPRI
;
323 ret
= ppoll(ufds
, MAX_FDS
, nullptr, nullptr);
327 } else if (ret
> 0) {
328 ret
= read(wait_fd
, buf
, BUF_SIZE
);
330 PERROR("[ppoll] read");
334 for (i
= 0; i
< MAX_FDS
; i
++) {
344 static void test_epoll(FILE *validation_output_file
)
348 struct epoll_event epoll_event
;
350 epollfd
= epoll_create(NB_FD
);
352 PERROR("[epoll] create");
356 ret
= fprintf(validation_output_file
, ", \"epoll_wait_fd\": %i", epollfd
);
358 PERROR("[epoll] Failed to write test validation output");
362 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
363 epoll_event
.data
.fd
= wait_fd
;
364 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
366 PERROR("[epoll] add");
371 ret
= epoll_wait(epollfd
, &epoll_event
, 1, timeout
);
373 ret
= epoll_wait(epollfd
, &epoll_event
, 1, -1);
377 ret
= read(wait_fd
, buf
, BUF_SIZE
);
379 PERROR("[epoll] read");
381 } else if (ret
!= 0) {
382 PERROR("epoll_wait");
386 ret
= close(epollfd
);
394 static void test_epoll_pwait(FILE *validation_output_file
)
398 struct epoll_event epoll_event
;
400 epollfd
= epoll_create(NB_FD
);
402 PERROR("[epoll_pwait] create");
406 ret
= fprintf(validation_output_file
, ", \"epoll_pwait_fd\": %i", epollfd
);
408 PERROR("[epoll_pwait] Failed to write test validation output");
412 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
413 epoll_event
.data
.fd
= wait_fd
;
414 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
416 PERROR("[epoll_pwait] add");
421 ret
= epoll_pwait(epollfd
, &epoll_event
, 1, timeout
, nullptr);
423 ret
= epoll_pwait(epollfd
, &epoll_event
, 1, -1, nullptr);
427 ret
= read(wait_fd
, buf
, BUF_SIZE
);
429 PERROR("[epoll_pwait] read");
431 } else if (ret
!= 0) {
432 PERROR("epoll_pwait");
436 ret
= close(epollfd
);
444 static void run_working_cases(FILE *validation_output_file
)
451 * We need an input pipe for some cases and stdin might
452 * have random data, so we create a dummy pipe for this
453 * test to make sure we are running under clean conditions.
455 ret
= pipe(pipe_fds
);
460 wait_fd
= pipe_fds
[0];
463 #ifdef sys_pselect6_time64
464 test_pselect_time64();
467 #endif /* sys_pselect6_time64 */
471 #ifdef sys_ppoll_time64
475 #endif /* sys_ppoll_time64 */
477 ret
= fprintf(validation_output_file
, "{\"pid\": %i", getpid());
479 PERROR("Failed to write pid to test validation file");
483 test_epoll(validation_output_file
);
484 test_epoll_pwait(validation_output_file
);
487 ret
= close(pipe_fds
[0]);
491 ret
= close(pipe_fds
[1]);
497 ret
= fputs(" }", validation_output_file
);
499 PERROR("Failed to close JSON dictionary in test validation file");
508 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
509 * cleanly fail with a "Invalid argument".
510 * The event should contain an empty array of FDs and overflow = 1.
512 static void generic_ppoll_fds_ulong_max(long int syscall_id
)
514 struct pollfd ufds
[NB_FD
];
518 ufds
[0].fd
= wait_fd
;
519 ufds
[0].events
= POLLIN
| POLLPRI
;
521 /* ppoll and/or ppoll_time64 are used, depending on platform support. */
522 ret
= syscall(syscall_id
, ufds
, ULONG_MAX
, NULL
, NULL
);
524 /* Expected error. */
525 } else if (ret
> 0) {
526 ret
= read(wait_fd
, buf
, BUF_SIZE
);
528 PERROR("Failed to read from wait file descriptor");
534 * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
535 * segfault (eventually with a "*** stack smashing detected ***" message).
536 * The event should contain an array of 100 FDs filled with garbage.
538 static void generic_ppoll_fds_buffer_overflow(long int syscall_id
)
540 struct pollfd ufds
[NB_FD
];
544 ufds
[0].fd
= wait_fd
;
545 ufds
[0].events
= POLLIN
| POLLPRI
;
547 /* ppoll and/or ppoll_time64 are used, depending on platform support. */
548 ret
= syscall(syscall_id
, ufds
, 100, NULL
, NULL
);
550 PERROR("Failed to wait using ppoll/ppoll_time64");
551 } else if (ret
> 0) {
552 ret
= read(wait_fd
, buf
, BUF_SIZE
);
554 PERROR("Failed to read from wait file descriptor");
559 static void ppoll_fds_ulong_max(FILE *validation_output_file
__attribute__((unused
)))
561 #ifdef SYS_ppoll_time64
562 generic_ppoll_fds_ulong_max(SYS_ppoll_time64
);
564 generic_ppoll_fds_ulong_max(SYS_ppoll
);
565 #endif /* SYS_ppoll_time64 */
568 static void ppoll_fds_buffer_overflow(FILE *validation_output_file
__attribute__((unused
)))
570 #ifdef SYS_ppoll_time64
571 generic_ppoll_fds_buffer_overflow(SYS_ppoll_time64
);
573 generic_ppoll_fds_buffer_overflow(SYS_ppoll
);
574 #endif /* SYS_ppoll_time64 */
578 * Pass an invalid file descriptor to pselect6(). The syscall should return
579 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
581 static void generic_invalid_fd(long int syscall_id
)
589 * Open a file, close it and use the closed FD in the pselect6 call.
591 fd
= open("/dev/null", O_RDONLY
);
593 PERROR("Failed to open /dev/null");
599 PERROR("Failed to close /dev/null file descriptor");
606 ret
= syscall(syscall_id
, fd
+ 1, &rfds
, NULL
, NULL
, NULL
, NULL
);
608 /* Expected error. */
610 ret
= read(wait_fd
, buf
, BUF_SIZE
);
612 PERROR("Failed to read from wait file descriptor");
620 * Invalid pointer as writefds, should output a ppoll event
623 static void generic_invalid_pointer(int syscall_id
)
628 void *invalid
= (void *) 0x42;
631 FD_SET(wait_fd
, &rfds
);
633 ret
= syscall(syscall_id
, 1, &rfds
, (fd_set
*) invalid
, NULL
, NULL
, NULL
);
635 /* Expected error. */
637 ret
= read(wait_fd
, buf
, BUF_SIZE
);
639 PERROR("Failed to read from wait file descriptor");
644 static void pselect_invalid_fd(FILE *validation_output_file
__attribute__((unused
)))
646 #ifdef SYS_pselect6_time64
647 generic_invalid_fd(SYS_pselect6_time64
);
649 generic_invalid_fd(SYS_pselect6
);
650 #endif /* SYS_pselect6_time64 */
654 * Invalid pointer as writefds, should output a ppoll event
657 static void pselect_invalid_pointer(FILE *validation_output_file
__attribute__((unused
)))
659 #ifdef SYS_pselect6_time64
660 generic_invalid_pointer(SYS_pselect6_time64
);
662 generic_invalid_pointer(SYS_pselect6
);
663 #endif /* SYS_pselect6_time64 */
667 * Pass an invalid pointer to epoll_pwait, should fail with
668 * "Bad address", the event returns 0 FDs.
670 static void epoll_pwait_invalid_pointer(FILE *validation_output_file
)
674 struct epoll_event epoll_event
;
675 void *invalid
= (void *) 0x42;
677 epollfd
= epoll_create(NB_FD
);
679 PERROR("[epoll_pwait] create");
683 ret
= fprintf(validation_output_file
, "{\"epollfd\": %i, \"pid\": %i }", epollfd
, getpid());
685 PERROR("[epoll_pwait] Failed to write test validation output");
689 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
690 epoll_event
.data
.fd
= wait_fd
;
691 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
693 PERROR("[epoll_pwait] add");
697 ret
= syscall(SYS_epoll_pwait
, epollfd
, (struct epoll_event
*) invalid
, 1, -1, NULL
);
700 ret
= read(wait_fd
, buf
, BUF_SIZE
);
702 PERROR("[epoll_pwait] read");
704 } else if (ret
!= 0) {
705 /* Expected error. */
709 ret
= close(epollfd
);
718 * Set maxevents to INT_MAX, should output "Invalid argument"
719 * The event should return an empty array.
721 static void epoll_pwait_int_max(FILE *validation_output_file
)
725 struct epoll_event epoll_event
;
727 epollfd
= epoll_create(NB_FD
);
729 PERROR("[epoll_pwait] create");
733 ret
= fprintf(validation_output_file
, "{\"epollfd\": %i, \"pid\": %i }", epollfd
, getpid());
735 PERROR("[epoll_pwait] Failed to write test validation output");
739 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
740 epoll_event
.data
.fd
= wait_fd
;
741 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
743 PERROR("[epoll_pwait] add");
747 ret
= syscall(SYS_epoll_pwait
, epollfd
, &epoll_event
, INT_MAX
, -1, NULL
);
750 ret
= read(wait_fd
, buf
, BUF_SIZE
);
752 PERROR("[epoll_pwait] read");
754 } else if (ret
!= 0) {
755 /* Expected error. */
759 ret
= close(epollfd
);
767 static void *ppoll_writer(void *arg
)
769 struct ppoll_thread_data
*data
= (struct ppoll_thread_data
*) arg
;
771 while (!stop_thread
) {
772 memset(data
->ufds
, data
->value
, MAX_FDS
* sizeof(struct pollfd
));
779 static void do_ppoll(int *fds
, struct pollfd
*ufds
)
786 ts
.tv_nsec
= 1 * MSEC_PER_NSEC
;
788 for (i
= 0; i
< MAX_FDS
; i
++) {
790 ufds
[i
].events
= POLLIN
| POLLPRI
;
793 ret
= ppoll(ufds
, MAX_FDS
, &ts
, nullptr);
797 } else if (ret
> 0) {
798 ret
= read(wait_fd
, buf
, BUF_SIZE
);
800 PERROR("[ppoll] read");
805 static void stress_ppoll(int *fds
, int value
)
809 struct ppoll_thread_data thread_data
;
810 struct pollfd ufds
[MAX_FDS
];
812 thread_data
.ufds
= ufds
;
813 thread_data
.value
= value
;
816 ret
= pthread_create(&writer
, nullptr, &ppoll_writer
, (void *) &thread_data
);
818 fprintf(stderr
, "[error] pthread_create\n");
821 for (iter
= 0; iter
< NR_ITER
; iter
++) {
825 ret
= pthread_join(writer
, nullptr);
827 fprintf(stderr
, "[error] pthread_join\n");
835 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
839 * - memset to INT_MAX
840 * Waits for input, but also set a timeout in case the input FD is overwritten
841 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
842 * resulting trace is big (20MB).
844 * ppoll should work as expected and the trace should be readable at the end.
846 static void ppoll_concurrent_write(FILE *validation_output_file
__attribute__((unused
)))
848 int i
, ret
, fds
[MAX_FDS
];
850 for (i
= 0; i
< MAX_FDS
; i
++) {
851 fds
[i
] = dup(wait_fd
);
857 stress_ppoll(fds
, 0);
858 stress_ppoll(fds
, 1);
859 stress_ppoll(fds
, INT_MAX
);
861 for (i
= 0; i
< MAX_FDS
; i
++) {
871 static void *epoll_pwait_writer(void *addr
)
873 srand(time(nullptr));
875 while (!stop_thread
) {
877 munmap(addr
, MAX_FDS
* sizeof(struct epoll_event
));
884 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
885 * buffer allocated for the returned data. This should randomly segfault.
886 * The trace should be readable and no kernel OOPS should occur.
888 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file
)
890 int ret
, epollfd
, i
, fds
[MAX_FDS
];
892 struct epoll_event
*epoll_event
;
895 for (i
= 0; i
< MAX_FDS
; i
++) {
898 epollfd
= epoll_create(MAX_FDS
);
900 PERROR("[epoll_pwait] create");
904 ret
= fprintf(validation_output_file
, "{\"epollfd\": %i, \"pid\": %i }", epollfd
, getpid());
906 PERROR("[epoll_pwait] Failed to write test validation output");
910 epoll_event
= (struct epoll_event
*) mmap(nullptr,
911 MAX_FDS
* sizeof(struct epoll_event
),
912 PROT_READ
| PROT_WRITE
,
913 MAP_PRIVATE
| MAP_ANONYMOUS
,
916 if (epoll_event
== MAP_FAILED
) {
921 for (i
= 0; i
< MAX_FDS
; i
++) {
922 fds
[i
] = dup(wait_fd
);
926 epoll_event
[i
].events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
927 epoll_event
[i
].data
.fd
= fds
[i
];
928 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fds
[i
], epoll_event
);
930 PERROR("[epoll_pwait] add");
935 ret
= pthread_create(&writer
, nullptr, &epoll_pwait_writer
, (void *) epoll_event
);
937 fprintf(stderr
, "[error] pthread_create\n");
941 ret
= epoll_pwait(epollfd
, epoll_event
, 1, 1, nullptr);
944 ret
= read(wait_fd
, buf
, BUF_SIZE
);
946 PERROR("[epoll_pwait] read");
948 } else if (ret
!= 0) {
949 /* Expected error. */
953 ret
= pthread_join(writer
, nullptr);
955 fprintf(stderr
, "[error] pthread_join\n");
959 for (i
= 0; i
< MAX_FDS
; i
++) {
966 ret
= munmap(epoll_event
, MAX_FDS
* sizeof(struct epoll_event
));
972 ret
= close(epollfd
);
980 static void print_list()
982 printf("Test list (-t X):\n");
984 for (size_t test_id
= 0; test_id
< ARRAY_SIZE(test_cases
); test_id
++) {
985 printf("\t%zu: %s - %s\n",
987 test_cases
[test_id
].name
,
988 test_cases
[test_id
].description
);
992 static void print_test_syscalls()
994 const char *supported_syscalls
[] = {
998 #if defined SYS_pselect6_time64 && defined SYS_pselect6
1001 #elif defined SYS_pselect6_time32 ^ defined SYS_pselect6
1003 #endif /* SYS_pselect6_time64 && defined SYS_pselect6 */
1007 #if defined SYS_ppoll && defined SYS_ppoll_time64
1010 #elif defined SYS_ppoll ^ defined SYS_ppoll_time64
1012 #endif /* defined SYS_ppoll && defined SYS_ppoll_time64 */
1013 #ifdef SYS_epoll_ctl
1016 #ifdef SYS_epoll_wait
1019 #ifdef SYS_epoll_pwait
1024 for (size_t i
= 0; i
< ARRAY_SIZE(supported_syscalls
); i
++) {
1025 fputs(supported_syscalls
[i
], stdout
);
1026 fputs(i
!= ARRAY_SIZE(supported_syscalls
) - 1 ? "," : "\n", stdout
);
1030 int main(int argc
, const char **argv
)
1033 const char *test_name
;
1035 struct rlimit open_lim
;
1036 FILE *test_validation_output_file
= nullptr;
1037 const char *test_validation_output_file_path
= nullptr;
1038 struct poptOption optionsTable
[] = {
1039 { "test", 't', POPT_ARG_STRING
, &test_name
, 0, "Name of test to run", nullptr },
1040 { "list-tests", 'l', 0, nullptr, 'l', "List tests (-t X)", nullptr },
1041 { "list-supported-test-syscalls",
1046 "List supported test syscalls",
1048 { "validation-file",
1051 &test_validation_output_file_path
,
1055 POPT_AUTOHELP
{ nullptr, 0, 0, nullptr, 0, nullptr, nullptr }
1057 const struct test_case
*test_case
;
1058 size_t test_case_id
;
1060 optCon
= poptGetContext(nullptr, argc
, argv
, optionsTable
, 0);
1063 poptPrintUsage(optCon
, stderr
, 0);
1070 while ((c
= poptGetNextOpt(optCon
)) >= 0) {
1076 print_test_syscalls();
1081 if (!test_validation_output_file_path
) {
1082 fprintf(stderr
, "A test validation file path is required (--validation-file/-o)\n");
1087 test_validation_output_file
= fopen(test_validation_output_file_path
, "w+");
1088 if (!test_validation_output_file
) {
1089 PERROR("Failed to create test validation output file at '%s'",
1090 test_validation_output_file_path
);
1095 open_lim
.rlim_cur
= MAX_FDS
+ MIN_NR_FDS
;
1096 open_lim
.rlim_max
= MAX_FDS
+ MIN_NR_FDS
;
1098 ret
= setrlimit(RLIMIT_NOFILE
, &open_lim
);
1100 PERROR("setrlimit");
1105 * Some tests might segfault, but we need the getpid() to be output
1106 * for the validation, disabling the buffering on the validation file
1109 setbuf(test_validation_output_file
, nullptr);
1110 wait_fd
= STDIN_FILENO
;
1112 /* Test case id is 1-based. */
1113 for (test_case_id
= 0; test_case_id
< ARRAY_SIZE(test_cases
); test_case_id
++) {
1114 if (!strcmp(test_cases
[test_case_id
].name
, test_name
)) {
1119 if (test_case_id
== ARRAY_SIZE(test_cases
)) {
1120 poptPrintUsage(optCon
, stderr
, 0);
1125 test_case
= &test_cases
[test_case_id
];
1127 timeout
= test_case
->timeout
;
1128 if (!test_case
->produces_validation_info
) {
1130 * All test cases need to provide, at minimum, the pid of the
1133 ret
= fprintf(test_validation_output_file
, "{\"pid\": %i }", getpid());
1135 PERROR("Failed to write application pid to test validation file");
1140 test_case
->run(test_validation_output_file
);
1143 if (test_validation_output_file
) {
1144 const int close_ret
= fclose(test_validation_output_file
);
1147 PERROR("Failed to close test output file");
1150 poptFreeContext(optCon
);