]> git.ipfire.org Git - thirdparty/glibc.git/blame - test-skeleton.c
Refactor M_ macros defined in libm-test.inc
[thirdparty/glibc.git] / test-skeleton.c
CommitLineData
80a18298 1/* Skeleton for test programs.
f7a9f785 2 Copyright (C) 1998-2016 Free Software Foundation, Inc.
41bdb6e2 3 This file is part of the GNU C Library.
80a18298
UD
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
80a18298
UD
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
80a18298 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
80a18298 19
d7a05d07 20#include <assert.h>
e1d8e1b7 21#include <errno.h>
c5bb8e23 22#include <fcntl.h>
80a18298 23#include <getopt.h>
854278df 24#include <malloc.h>
c5bb8e23 25#include <paths.h>
b9337b6a 26#include <search.h>
80a18298
UD
27#include <signal.h>
28#include <stdio.h>
29#include <stdlib.h>
4380ef5e 30#include <string.h>
80a18298
UD
31#include <unistd.h>
32#include <sys/resource.h>
33#include <sys/wait.h>
63b11dd1 34#include <sys/param.h>
fa4a36fd 35#include <time.h>
80a18298
UD
36
37/* The test function is normally called `do_test' and it is called
38 with argc and argv as the arguments. We nevertheless provide the
39 possibility to overwrite this name. */
40#ifndef TEST_FUNCTION
41# define TEST_FUNCTION do_test (argc, argv)
42#endif
43
63b11dd1
RM
44#ifndef TEST_DATA_LIMIT
45# define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with. */
46#endif
80a18298 47
b0b88abc 48#ifndef TIMEOUT
a28605b2
MF
49 /* Default timeout is twenty seconds. Tests should normally complete faster
50 than this, but if they don't, that's abnormal (a bug) anyways. */
51# define TIMEOUT 20
b0b88abc
RM
52#endif
53
80a18298
UD
54#define OPT_DIRECT 1000
55#define OPT_TESTDIR 1001
56
57static struct option options[] =
58{
59#ifdef CMDLINE_OPTIONS
60 CMDLINE_OPTIONS
61#endif
62 { "direct", no_argument, NULL, OPT_DIRECT },
63 { "test-dir", required_argument, NULL, OPT_TESTDIR },
64 { NULL, 0, NULL, 0 }
65};
66
67/* PID of the test itself. */
608c5afd 68static pid_t pid;
80a18298
UD
69
70/* Directory to place temporary files in. */
71static const char *test_dir;
72
b9337b6a 73/* List of temporary files. */
51eecc4a 74struct temp_name_list
b9337b6a
UD
75{
76 struct qelem q;
cc8dcf96 77 char *name;
51eecc4a 78} *temp_name_list;
b9337b6a
UD
79
80/* Add temporary files in list. */
9c0592ab 81static void
5cd6f8f7 82__attribute__ ((unused))
b9337b6a
UD
83add_temp_file (const char *name)
84{
51eecc4a
AJ
85 struct temp_name_list *newp
86 = (struct temp_name_list *) calloc (sizeof (*newp), 1);
cc8dcf96
FW
87 char *newname = strdup (name);
88 if (newp != NULL && newname != NULL)
b9337b6a 89 {
cc8dcf96 90 newp->name = newname;
51eecc4a
AJ
91 if (temp_name_list == NULL)
92 temp_name_list = (struct temp_name_list *) &newp->q;
b9337b6a 93 else
51eecc4a 94 insque (newp, temp_name_list);
b9337b6a 95 }
cc8dcf96
FW
96 else
97 free (newp);
b9337b6a
UD
98}
99
100/* Delete all temporary files. */
9c0592ab 101static void
b9337b6a
UD
102delete_temp_files (void)
103{
51eecc4a 104 while (temp_name_list != NULL)
b9337b6a 105 {
51eecc4a 106 remove (temp_name_list->name);
cc8dcf96
FW
107 free (temp_name_list->name);
108
109 struct temp_name_list *next
110 = (struct temp_name_list *) temp_name_list->q.q_forw;
111 free (temp_name_list);
112 temp_name_list = next;
b9337b6a
UD
113 }
114}
115
cc8dcf96
FW
116/* Create a temporary file. Return the opened file descriptor on
117 success, or -1 on failure. Write the file name to *FILENAME if
118 FILENAME is not NULL. In this case, the caller is expected to free
119 *FILENAME. */
10e62564
UD
120static int
121__attribute__ ((unused))
122create_temp_file (const char *base, char **filename)
123{
124 char *fname;
125 int fd;
126
127 fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base)
128 + sizeof ("XXXXXX"));
129 if (fname == NULL)
130 {
131 puts ("out of memory");
132 return -1;
133 }
134 strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
135
136 fd = mkstemp (fname);
137 if (fd == -1)
138 {
139 printf ("cannot open temporary file '%s': %m\n", fname);
140 free (fname);
141 return -1;
142 }
143
144 add_temp_file (fname);
145 if (filename != NULL)
146 *filename = fname;
cc8dcf96
FW
147 else
148 free (fname);
10e62564
UD
149
150 return fd;
151}
152
80a18298 153/* Timeout handler. We kill the child and exit with an error. */
9c0592ab 154static void
8c0b7170 155__attribute__ ((noreturn))
85fda49b 156signal_handler (int sig __attribute__ ((unused)))
80a18298
UD
157{
158 int killed;
b79e3737 159 int status;
80a18298 160
d7a05d07
MR
161 assert (pid > 1);
162 /* Kill the whole process group. */
163 kill (-pid, SIGKILL);
164 /* In case setpgid failed in the child, kill it individually too. */
80a18298
UD
165 kill (pid, SIGKILL);
166
167 /* Wait for it to terminate. */
6d0e6e84
UD
168 int i;
169 for (i = 0; i < 5; ++i)
170 {
171 killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
172 if (killed != 0)
173 break;
174
175 /* Delay, give the system time to process the kill. If the
176 nanosleep() call return prematurely, all the better. We
177 won't restart it since this probably means the child process
178 finally died. */
33192609
UD
179 struct timespec ts;
180 ts.tv_sec = 0;
181 ts.tv_nsec = 100000000;
6d0e6e84
UD
182 nanosleep (&ts, NULL);
183 }
80a18298
UD
184 if (killed != 0 && killed != pid)
185 {
c5c13355 186 printf ("Failed to kill test process: %m\n");
80a18298
UD
187 exit (1);
188 }
189
190#ifdef CLEANUP_HANDLER
191 CLEANUP_HANDLER;
192#endif
193
85fda49b
UD
194 if (sig == SIGINT)
195 {
196 signal (sig, SIG_DFL);
197 raise (sig);
198 }
199
4614167a
UD
200 /* If we expected this signal: good! */
201#ifdef EXPECTED_SIGNAL
202 if (EXPECTED_SIGNAL == SIGALRM)
203 exit (0);
204#endif
205
6d0e6e84 206 if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
c5c13355 207 puts ("Timed out: killed the child process");
b79e3737 208 else if (WIFSTOPPED (status))
c5c13355
WN
209 printf ("Timed out: the child process was %s\n",
210 strsignal (WSTOPSIG (status)));
b79e3737 211 else if (WIFSIGNALED (status))
c5c13355
WN
212 printf ("Timed out: the child process got signal %s\n",
213 strsignal (WTERMSIG (status)));
b79e3737 214 else
c5c13355
WN
215 printf ("Timed out: killed the child process but it exited %d\n",
216 WEXITSTATUS (status));
80a18298
UD
217
218 /* Exit with an error. */
219 exit (1);
220}
221
02242448
TMQMF
222/* Avoid all the buffer overflow messages on stderr. */
223static void
224__attribute__ ((unused))
225ignore_stderr (void)
226{
227 int fd = open (_PATH_DEVNULL, O_WRONLY);
228 if (fd == -1)
229 close (STDERR_FILENO);
230 else
231 {
232 dup2 (fd, STDERR_FILENO);
233 close (fd);
234 }
235 setenv ("LIBC_FATAL_STDERR_", "1", 1);
236}
237
c5bb8e23
MF
238/* Set fortification error handler. Used when tests want to verify that bad
239 code is caught by the library. */
240static void
241__attribute__ ((unused))
242set_fortify_handler (void (*handler) (int sig))
243{
244 struct sigaction sa;
245
246 sa.sa_handler = handler;
247 sa.sa_flags = 0;
248 sigemptyset (&sa.sa_mask);
249
250 sigaction (SIGABRT, &sa, NULL);
02242448 251 ignore_stderr ();
c5bb8e23
MF
252}
253
496405af
MF
254/* Show people how to run the program. */
255static void
256usage (void)
257{
258 size_t i;
259
260 printf ("Usage: %s [options]\n"
261 "\n"
262 "Environment Variables:\n"
263 " TIMEOUTFACTOR An integer used to scale the timeout\n"
264 " TMPDIR Where to place temporary files\n"
265 "\n",
266 program_invocation_short_name);
267 printf ("Options:\n");
268 for (i = 0; options[i].name; ++i)
269 {
270 int indent;
271
272 indent = printf (" --%s", options[i].name);
273 if (options[i].has_arg == required_argument)
274 indent += printf (" <arg>");
275 printf ("%*s", 25 - indent, "");
276 switch (options[i].val)
277 {
278 case OPT_DIRECT:
279 printf ("Run the test directly (instead of forking & monitoring)");
280 break;
281 case OPT_TESTDIR:
282 printf ("Override the TMPDIR env var");
283 break;
284 }
285 printf ("\n");
286 }
287}
288
80a18298
UD
289/* We provide the entry point here. */
290int
291main (int argc, char *argv[])
292{
293 int direct = 0; /* Directly call the test function? */
294 int status;
295 int opt;
dc391246 296 unsigned int timeoutfactor = 1;
608c5afd 297 pid_t termpid;
80a18298 298
854278df
UD
299 /* Make uses of freed and uninitialized memory known. */
300 mallopt (M_PERTURB, 42);
301
e7c036b3
UD
302#ifdef STDOUT_UNBUFFERED
303 setbuf (stdout, NULL);
304#endif
305
6f1acb30 306 while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
80a18298
UD
307 switch (opt)
308 {
309 case '?':
496405af 310 usage ();
80a18298
UD
311 exit (1);
312 case OPT_DIRECT:
313 direct = 1;
314 break;
315 case OPT_TESTDIR:
316 test_dir = optarg;
317 break;
318#ifdef CMDLINE_PROCESS
319 CMDLINE_PROCESS
320#endif
321 }
322
dc391246
UD
323 /* If set, read the test TIMEOUTFACTOR value from the environment.
324 This value is used to scale the default test timeout values. */
325 char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
326 if (envstr_timeoutfactor != NULL)
327 {
328 char *envstr_conv = envstr_timeoutfactor;
329 unsigned long int env_fact;
330
331 env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
332 if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
333 timeoutfactor = MAX (env_fact, 1);
334 }
335
80a18298
UD
336 /* Set TMPDIR to specified test directory. */
337 if (test_dir != NULL)
338 {
339 setenv ("TMPDIR", test_dir, 1);
340
341 if (chdir (test_dir) < 0)
342 {
c5c13355 343 printf ("chdir: %m\n");
80a18298
UD
344 exit (1);
345 }
346 }
b9337b6a
UD
347 else
348 {
349 test_dir = getenv ("TMPDIR");
350 if (test_dir == NULL || test_dir[0] == '\0')
351 test_dir = "/tmp";
352 }
80a18298 353
6b9c2e67
UD
354 /* Make sure we see all message, even those on stdout. */
355 setvbuf (stdout, NULL, _IONBF, 0);
356
b0b88abc 357 /* Make sure temporary files are deleted. */
310b3460
UD
358 atexit (delete_temp_files);
359
726b7b0f 360 /* Correct for the possible parameters. */
55033a44 361 argv[optind - 1] = argv[0];
726b7b0f
UD
362 argv += optind - 1;
363 argc -= optind - 1;
364
310b3460
UD
365 /* Call the initializing function, if one is available. */
366#ifdef PREPARE
367 PREPARE (argc, argv);
368#endif
369
b0b88abc
RM
370 const char *envstr_direct = getenv ("TEST_DIRECT");
371 if (envstr_direct != NULL)
372 {
373 FILE *f = fopen (envstr_direct, "w");
374 if (f == NULL)
375 {
376 printf ("cannot open TEST_DIRECT output file '%s': %m\n",
377 envstr_direct);
378 exit (1);
379 }
380
381 fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", TIMEOUT, timeoutfactor);
382#ifdef EXPECTED_STATUS
383 fprintf (f, "exit=%u\n", EXPECTED_STATUS);
384#endif
385#ifdef EXPECTED_SIGNAL
386 switch (EXPECTED_SIGNAL)
387 {
388 default: abort ();
389# define init_sig(signo, name, text) \
390 case signo: fprintf (f, "signal=%s\n", name); break;
391# include <siglist.h>
392# undef init_sig
393 }
394#endif
395
396 if (temp_name_list != NULL)
397 {
330fadfc 398 struct temp_name_list *n;
b0b88abc 399 fprintf (f, "temp_files=(\n");
330fadfc 400 for (n = temp_name_list;
b0b88abc
RM
401 n != NULL;
402 n = (struct temp_name_list *) n->q.q_forw)
403 fprintf (f, " '%s'\n", n->name);
404 fprintf (f, ")\n");
405 }
406
407 fclose (f);
408 direct = 1;
409 }
410
80a18298
UD
411 /* If we are not expected to fork run the function immediately. */
412 if (direct)
413 return TEST_FUNCTION;
414
415 /* Set up the test environment:
416 - prevent core dumps
417 - set up the timer
418 - fork and execute the function. */
419
420 pid = fork ();
421 if (pid == 0)
422 {
423 /* This is the child. */
424#ifdef RLIMIT_CORE
425 /* Try to avoid dumping core. */
426 struct rlimit core_limit;
427 core_limit.rlim_cur = 0;
428 core_limit.rlim_max = 0;
429 setrlimit (RLIMIT_CORE, &core_limit);
430#endif
63b11dd1 431
b79e3737
RM
432 /* We put the test process in its own pgrp so that if it bogusly
433 generates any job control signals, they won't hit the whole build. */
d7a05d07
MR
434 if (setpgid (0, 0) != 0)
435 printf ("Failed to set the process group ID: %m\n");
b79e3737 436
80a18298
UD
437 /* Execute the test function and exit with the return value. */
438 exit (TEST_FUNCTION);
439 }
440 else if (pid < 0)
441 {
c5c13355 442 printf ("Cannot fork test program: %m\n");
80a18298
UD
443 exit (1);
444 }
445
446 /* Set timeout. */
85fda49b 447 signal (SIGALRM, signal_handler);
dc391246 448 alarm (TIMEOUT * timeoutfactor);
80a18298 449
85fda49b
UD
450 /* Make sure we clean up if the wrapper gets interrupted. */
451 signal (SIGINT, signal_handler);
452
80a18298 453 /* Wait for the regular termination. */
53854476 454 termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
608c5afd 455 if (termpid == -1)
80a18298 456 {
608c5afd
UD
457 printf ("Waiting for test program failed: %m\n");
458 exit (1);
459 }
460 if (termpid != pid)
461 {
462 printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
463 (long int) pid, (long int) termpid);
80a18298
UD
464 exit (1);
465 }
466
fffa1cf8
LH
467 /* Process terminated normaly without timeout etc. */
468 if (WIFEXITED (status))
80a18298 469 {
ede0f73a 470#ifndef EXPECTED_STATUS
fffa1cf8
LH
471# ifndef EXPECTED_SIGNAL
472 /* Simply exit with the return value of the test. */
473 return WEXITSTATUS (status);
474# else
475 printf ("Expected signal '%s' from child, got none\n",
476 strsignal (EXPECTED_SIGNAL));
477 exit (1);
478# endif
ede0f73a 479#else
fffa1cf8
LH
480 if (WEXITSTATUS (status) != EXPECTED_STATUS)
481 {
482 printf ("Expected status %d, got %d\n",
483 EXPECTED_STATUS, WEXITSTATUS (status));
484 exit (1);
485 }
486
487 return 0;
488#endif
489 }
490 /* Process was killed by timer or other signal. */
491 else
ede0f73a 492 {
fffa1cf8
LH
493#ifndef EXPECTED_SIGNAL
494 printf ("Didn't expect signal from child: got `%s'\n",
495 strsignal (WTERMSIG (status)));
ede0f73a 496 exit (1);
fffa1cf8
LH
497#else
498 if (WTERMSIG (status) != EXPECTED_SIGNAL)
499 {
500 printf ("Incorrect signal from child: got `%s', need `%s'\n",
501 strsignal (WTERMSIG (status)),
502 strsignal (EXPECTED_SIGNAL));
503 exit (1);
504 }
ede0f73a 505
fffa1cf8 506 return 0;
ede0f73a 507#endif
fffa1cf8 508 }
80a18298 509}