Fix assertion failure on test timeout
[glibc.git] / support / support_test_main.c
blob0582230aecc971fc4b838d487c6e883f07901788
1 /* Main worker function for the test driver.
2 Copyright (C) 1998-2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <support/test-driver.h>
20 #include <support/temp_file-internal.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <getopt.h>
25 #include <malloc.h>
26 #include <signal.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/param.h>
31 #include <sys/resource.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <time.h>
35 #include <unistd.h>
37 static const struct option default_options[] =
39 { "direct", no_argument, NULL, OPT_DIRECT },
40 { "test-dir", required_argument, NULL, OPT_TESTDIR },
41 { NULL, 0, NULL, 0 }
44 /* Show people how to run the program. */
45 static void
46 usage (const struct option *options)
48 size_t i;
50 printf ("Usage: %s [options]\n"
51 "\n"
52 "Environment Variables:\n"
53 " TIMEOUTFACTOR An integer used to scale the timeout\n"
54 " TMPDIR Where to place temporary files\n"
55 " TEST_COREDUMPS Do not disable coredumps if set\n"
56 "\n",
57 program_invocation_short_name);
58 printf ("Options:\n");
59 for (i = 0; options[i].name; ++i)
61 int indent;
63 indent = printf (" --%s", options[i].name);
64 if (options[i].has_arg == required_argument)
65 indent += printf (" <arg>");
66 printf ("%*s", 25 - indent, "");
67 switch (options[i].val)
69 case OPT_DIRECT:
70 printf ("Run the test directly (instead of forking & monitoring)");
71 break;
72 case OPT_TESTDIR:
73 printf ("Override the TMPDIR env var");
74 break;
76 printf ("\n");
80 /* The PID of the test process. */
81 static pid_t test_pid;
83 /* The cleanup handler passed to test_main. */
84 static void (*cleanup_function) (void);
86 /* Timeout handler. We kill the child and exit with an error. */
87 static void
88 __attribute__ ((noreturn))
89 signal_handler (int sig)
91 int killed;
92 int status;
94 assert (test_pid > 1);
95 /* Kill the whole process group. */
96 kill (-test_pid, SIGKILL);
97 /* In case setpgid failed in the child, kill it individually too. */
98 kill (test_pid, SIGKILL);
100 /* Wait for it to terminate. */
101 int i;
102 for (i = 0; i < 5; ++i)
104 killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED);
105 if (killed != 0)
106 break;
108 /* Delay, give the system time to process the kill. If the
109 nanosleep() call return prematurely, all the better. We
110 won't restart it since this probably means the child process
111 finally died. */
112 struct timespec ts;
113 ts.tv_sec = 0;
114 ts.tv_nsec = 100000000;
115 nanosleep (&ts, NULL);
117 if (killed != 0 && killed != test_pid)
119 printf ("Failed to kill test process: %m\n");
120 exit (1);
123 if (cleanup_function != NULL)
124 cleanup_function ();
126 if (sig == SIGINT)
128 signal (sig, SIG_DFL);
129 raise (sig);
132 if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
133 puts ("Timed out: killed the child process");
134 else if (WIFSTOPPED (status))
135 printf ("Timed out: the child process was %s\n",
136 strsignal (WSTOPSIG (status)));
137 else if (WIFSIGNALED (status))
138 printf ("Timed out: the child process got signal %s\n",
139 strsignal (WTERMSIG (status)));
140 else
141 printf ("Timed out: killed the child process but it exited %d\n",
142 WEXITSTATUS (status));
144 /* Exit with an error. */
145 exit (1);
148 /* Run test_function or test_function_argv. */
149 static int
150 run_test_function (int argc, char **argv, const struct test_config *config)
152 if (config->test_function != NULL)
153 return config->test_function ();
154 else if (config->test_function_argv != NULL)
155 return config->test_function_argv (argc, argv);
156 else
158 printf ("error: no test function defined\n");
159 exit (1);
163 static bool test_main_called;
165 const char *test_dir = NULL;
168 support_test_main (int argc, char **argv, const struct test_config *config)
170 if (test_main_called)
172 printf ("error: test_main called for a second time\n");
173 exit (1);
175 test_main_called = true;
176 const struct option *options;
177 if (config->options != NULL)
178 options = config->options;
179 else
180 options = default_options;
182 cleanup_function = config->cleanup_function;
184 int direct = 0; /* Directly call the test function? */
185 int status;
186 int opt;
187 unsigned int timeoutfactor = 1;
188 pid_t termpid;
190 if (!config->no_mallopt)
192 /* Make uses of freed and uninitialized memory known. Do not
193 pull in a definition for mallopt if it has not been defined
194 already. */
195 extern __typeof__ (mallopt) mallopt __attribute__ ((weak));
196 if (mallopt != NULL)
197 mallopt (M_PERTURB, 42);
200 while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
201 switch (opt)
203 case '?':
204 usage (options);
205 exit (1);
206 case OPT_DIRECT:
207 direct = 1;
208 break;
209 case OPT_TESTDIR:
210 test_dir = optarg;
211 break;
212 default:
213 if (config->cmdline_function != NULL)
214 config->cmdline_function (opt);
217 /* If set, read the test TIMEOUTFACTOR value from the environment.
218 This value is used to scale the default test timeout values. */
219 char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
220 if (envstr_timeoutfactor != NULL)
222 char *envstr_conv = envstr_timeoutfactor;
223 unsigned long int env_fact;
225 env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
226 if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
227 timeoutfactor = MAX (env_fact, 1);
230 /* Set TMPDIR to specified test directory. */
231 if (test_dir != NULL)
233 setenv ("TMPDIR", test_dir, 1);
235 if (chdir (test_dir) < 0)
237 printf ("chdir: %m\n");
238 exit (1);
241 else
243 test_dir = getenv ("TMPDIR");
244 if (test_dir == NULL || test_dir[0] == '\0')
245 test_dir = "/tmp";
247 if (support_set_test_dir != NULL)
248 support_set_test_dir (test_dir);
250 int timeout = config->timeout;
251 if (timeout == 0)
252 timeout = DEFAULT_TIMEOUT;
254 /* Make sure we see all message, even those on stdout. */
255 setvbuf (stdout, NULL, _IONBF, 0);
257 /* Make sure temporary files are deleted. */
258 if (support_delete_temp_files != NULL)
259 atexit (support_delete_temp_files);
261 /* Correct for the possible parameters. */
262 argv[optind - 1] = argv[0];
263 argv += optind - 1;
264 argc -= optind - 1;
266 /* Call the initializing function, if one is available. */
267 if (config->prepare_function != NULL)
268 config->prepare_function (argc, argv);
270 const char *envstr_direct = getenv ("TEST_DIRECT");
271 if (envstr_direct != NULL)
273 FILE *f = fopen (envstr_direct, "w");
274 if (f == NULL)
276 printf ("cannot open TEST_DIRECT output file '%s': %m\n",
277 envstr_direct);
278 exit (1);
281 fprintf (f, "timeout=%u\ntimeoutfactor=%u\n",
282 config->timeout, timeoutfactor);
283 if (config->expected_status != 0)
284 fprintf (f, "exit=%u\n", config->expected_status);
285 if (config->expected_signal != 0)
286 fprintf (f, "signal=%s\n", strsignal (config->expected_signal));
288 if (support_print_temp_files != NULL)
289 support_print_temp_files (f);
291 fclose (f);
292 direct = 1;
295 bool disable_coredumps;
297 const char *coredumps = getenv ("TEST_COREDUMPS");
298 disable_coredumps = coredumps == NULL || coredumps[0] == '\0';
301 /* If we are not expected to fork run the function immediately. */
302 if (direct)
303 return run_test_function (argc, argv, config);
305 /* Set up the test environment:
306 - prevent core dumps
307 - set up the timer
308 - fork and execute the function. */
310 test_pid = fork ();
311 if (test_pid == 0)
313 /* This is the child. */
314 if (disable_coredumps)
316 /* Try to avoid dumping core. This is necessary because we
317 run the test from the source tree, and the coredumps
318 would end up there (and not in the build tree). */
319 struct rlimit core_limit;
320 core_limit.rlim_cur = 0;
321 core_limit.rlim_max = 0;
322 setrlimit (RLIMIT_CORE, &core_limit);
325 /* We put the test process in its own pgrp so that if it bogusly
326 generates any job control signals, they won't hit the whole build. */
327 if (setpgid (0, 0) != 0)
328 printf ("Failed to set the process group ID: %m\n");
330 /* Execute the test function and exit with the return value. */
331 exit (run_test_function (argc, argv, config));
333 else if (test_pid < 0)
335 printf ("Cannot fork test program: %m\n");
336 exit (1);
339 /* Set timeout. */
340 signal (SIGALRM, signal_handler);
341 alarm (timeout * timeoutfactor);
343 /* Make sure we clean up if the wrapper gets interrupted. */
344 signal (SIGINT, signal_handler);
346 /* Wait for the regular termination. */
347 termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0));
348 if (termpid == -1)
350 printf ("Waiting for test program failed: %m\n");
351 exit (1);
353 if (termpid != test_pid)
355 printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
356 (long int) test_pid, (long int) termpid);
357 exit (1);
360 /* Process terminated normaly without timeout etc. */
361 if (WIFEXITED (status))
363 if (config->expected_status == 0)
365 if (config->expected_signal == 0)
366 /* Simply exit with the return value of the test. */
367 return WEXITSTATUS (status);
368 else
370 printf ("Expected signal '%s' from child, got none\n",
371 strsignal (config->expected_signal));
372 exit (1);
375 else
377 /* Non-zero exit status is expected */
378 if (WEXITSTATUS (status) != config->expected_status)
380 printf ("Expected status %d, got %d\n",
381 config->expected_status, WEXITSTATUS (status));
382 exit (1);
385 return 0;
387 /* Process was killed by timer or other signal. */
388 else
390 if (config->expected_signal == 0)
392 printf ("Didn't expect signal from child: got `%s'\n",
393 strsignal (WTERMSIG (status)));
394 exit (1);
396 else if (WTERMSIG (status) != config->expected_signal)
398 printf ("Incorrect signal from child: got `%s', need `%s'\n",
399 strsignal (WTERMSIG (status)),
400 strsignal (config->expected_signal));
401 exit (1);
404 return 0;