]> git.ipfire.org Git - thirdparty/glibc.git/blame - test-skeleton.c
2016-06-09 Paul Pluzhnikov <ppluzhnikov@gmail.com>
[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
530bb2bf
PP
73static void
74oom_error (const char *fn, size_t size)
75{
76 printf ("%s: unable to allocate %zu bytes: %m\n", fn, size);
77 exit (1);
78}
79
80/* Allocate N bytes of memory dynamically, with error checking. */
81static void *
82__attribute__ ((used))
83xmalloc (size_t n)
84{
85 void *p;
86
87 p = malloc (n);
88 if (p == NULL)
89 oom_error ("malloc", n);
90 return p;
91}
92
93/* Allocate memory for N elements of S bytes, with error checking. */
94static void *
95__attribute__ ((used))
96xcalloc (size_t n, size_t s)
97{
98 void *p;
99
100 p = calloc (n, s);
101 if (p == NULL)
102 oom_error ("calloc", n * s);
103 return p;
104}
105
106/* Change the size of an allocated block of memory P to N bytes,
107 with error checking. */
108static void *
109__attribute__ ((used))
110xrealloc (void *p, size_t n)
111{
112 p = realloc (p, n);
113 if (p == NULL)
114 oom_error ("realloc", n);
115 return p;
116}
117
b9337b6a 118/* List of temporary files. */
51eecc4a 119struct temp_name_list
b9337b6a
UD
120{
121 struct qelem q;
cc8dcf96 122 char *name;
51eecc4a 123} *temp_name_list;
b9337b6a
UD
124
125/* Add temporary files in list. */
9c0592ab 126static void
5cd6f8f7 127__attribute__ ((unused))
b9337b6a
UD
128add_temp_file (const char *name)
129{
51eecc4a 130 struct temp_name_list *newp
530bb2bf 131 = (struct temp_name_list *) xcalloc (sizeof (*newp), 1);
cc8dcf96 132 char *newname = strdup (name);
530bb2bf 133 if (newname != NULL)
b9337b6a 134 {
cc8dcf96 135 newp->name = newname;
51eecc4a
AJ
136 if (temp_name_list == NULL)
137 temp_name_list = (struct temp_name_list *) &newp->q;
b9337b6a 138 else
51eecc4a 139 insque (newp, temp_name_list);
b9337b6a 140 }
cc8dcf96
FW
141 else
142 free (newp);
b9337b6a
UD
143}
144
145/* Delete all temporary files. */
9c0592ab 146static void
b9337b6a
UD
147delete_temp_files (void)
148{
51eecc4a 149 while (temp_name_list != NULL)
b9337b6a 150 {
51eecc4a 151 remove (temp_name_list->name);
cc8dcf96
FW
152 free (temp_name_list->name);
153
154 struct temp_name_list *next
155 = (struct temp_name_list *) temp_name_list->q.q_forw;
156 free (temp_name_list);
157 temp_name_list = next;
b9337b6a
UD
158 }
159}
160
cc8dcf96
FW
161/* Create a temporary file. Return the opened file descriptor on
162 success, or -1 on failure. Write the file name to *FILENAME if
163 FILENAME is not NULL. In this case, the caller is expected to free
164 *FILENAME. */
10e62564
UD
165static int
166__attribute__ ((unused))
167create_temp_file (const char *base, char **filename)
168{
169 char *fname;
170 int fd;
171
530bb2bf
PP
172 fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base)
173 + sizeof ("XXXXXX"));
10e62564
UD
174 strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
175
176 fd = mkstemp (fname);
177 if (fd == -1)
178 {
179 printf ("cannot open temporary file '%s': %m\n", fname);
180 free (fname);
181 return -1;
182 }
183
184 add_temp_file (fname);
185 if (filename != NULL)
186 *filename = fname;
cc8dcf96
FW
187 else
188 free (fname);
10e62564
UD
189
190 return fd;
191}
192
80a18298 193/* Timeout handler. We kill the child and exit with an error. */
9c0592ab 194static void
8c0b7170 195__attribute__ ((noreturn))
85fda49b 196signal_handler (int sig __attribute__ ((unused)))
80a18298
UD
197{
198 int killed;
b79e3737 199 int status;
80a18298 200
d7a05d07
MR
201 assert (pid > 1);
202 /* Kill the whole process group. */
203 kill (-pid, SIGKILL);
204 /* In case setpgid failed in the child, kill it individually too. */
80a18298
UD
205 kill (pid, SIGKILL);
206
207 /* Wait for it to terminate. */
6d0e6e84
UD
208 int i;
209 for (i = 0; i < 5; ++i)
210 {
211 killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
212 if (killed != 0)
213 break;
214
215 /* Delay, give the system time to process the kill. If the
216 nanosleep() call return prematurely, all the better. We
217 won't restart it since this probably means the child process
218 finally died. */
33192609
UD
219 struct timespec ts;
220 ts.tv_sec = 0;
221 ts.tv_nsec = 100000000;
6d0e6e84
UD
222 nanosleep (&ts, NULL);
223 }
80a18298
UD
224 if (killed != 0 && killed != pid)
225 {
c5c13355 226 printf ("Failed to kill test process: %m\n");
80a18298
UD
227 exit (1);
228 }
229
230#ifdef CLEANUP_HANDLER
231 CLEANUP_HANDLER;
232#endif
233
85fda49b
UD
234 if (sig == SIGINT)
235 {
236 signal (sig, SIG_DFL);
237 raise (sig);
238 }
239
4614167a
UD
240 /* If we expected this signal: good! */
241#ifdef EXPECTED_SIGNAL
242 if (EXPECTED_SIGNAL == SIGALRM)
243 exit (0);
244#endif
245
6d0e6e84 246 if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
c5c13355 247 puts ("Timed out: killed the child process");
b79e3737 248 else if (WIFSTOPPED (status))
c5c13355
WN
249 printf ("Timed out: the child process was %s\n",
250 strsignal (WSTOPSIG (status)));
b79e3737 251 else if (WIFSIGNALED (status))
c5c13355
WN
252 printf ("Timed out: the child process got signal %s\n",
253 strsignal (WTERMSIG (status)));
b79e3737 254 else
c5c13355
WN
255 printf ("Timed out: killed the child process but it exited %d\n",
256 WEXITSTATUS (status));
80a18298
UD
257
258 /* Exit with an error. */
259 exit (1);
260}
261
02242448
TMQMF
262/* Avoid all the buffer overflow messages on stderr. */
263static void
264__attribute__ ((unused))
265ignore_stderr (void)
266{
267 int fd = open (_PATH_DEVNULL, O_WRONLY);
268 if (fd == -1)
269 close (STDERR_FILENO);
270 else
271 {
272 dup2 (fd, STDERR_FILENO);
273 close (fd);
274 }
275 setenv ("LIBC_FATAL_STDERR_", "1", 1);
276}
277
c5bb8e23
MF
278/* Set fortification error handler. Used when tests want to verify that bad
279 code is caught by the library. */
280static void
281__attribute__ ((unused))
282set_fortify_handler (void (*handler) (int sig))
283{
284 struct sigaction sa;
285
286 sa.sa_handler = handler;
287 sa.sa_flags = 0;
288 sigemptyset (&sa.sa_mask);
289
290 sigaction (SIGABRT, &sa, NULL);
02242448 291 ignore_stderr ();
c5bb8e23
MF
292}
293
496405af
MF
294/* Show people how to run the program. */
295static void
296usage (void)
297{
298 size_t i;
299
300 printf ("Usage: %s [options]\n"
301 "\n"
302 "Environment Variables:\n"
303 " TIMEOUTFACTOR An integer used to scale the timeout\n"
304 " TMPDIR Where to place temporary files\n"
305 "\n",
306 program_invocation_short_name);
307 printf ("Options:\n");
308 for (i = 0; options[i].name; ++i)
309 {
310 int indent;
311
312 indent = printf (" --%s", options[i].name);
313 if (options[i].has_arg == required_argument)
314 indent += printf (" <arg>");
315 printf ("%*s", 25 - indent, "");
316 switch (options[i].val)
317 {
318 case OPT_DIRECT:
319 printf ("Run the test directly (instead of forking & monitoring)");
320 break;
321 case OPT_TESTDIR:
322 printf ("Override the TMPDIR env var");
323 break;
324 }
325 printf ("\n");
326 }
327}
328
80a18298
UD
329/* We provide the entry point here. */
330int
331main (int argc, char *argv[])
332{
333 int direct = 0; /* Directly call the test function? */
334 int status;
335 int opt;
dc391246 336 unsigned int timeoutfactor = 1;
608c5afd 337 pid_t termpid;
80a18298 338
854278df
UD
339 /* Make uses of freed and uninitialized memory known. */
340 mallopt (M_PERTURB, 42);
341
e7c036b3
UD
342#ifdef STDOUT_UNBUFFERED
343 setbuf (stdout, NULL);
344#endif
345
6f1acb30 346 while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
80a18298
UD
347 switch (opt)
348 {
349 case '?':
496405af 350 usage ();
80a18298
UD
351 exit (1);
352 case OPT_DIRECT:
353 direct = 1;
354 break;
355 case OPT_TESTDIR:
356 test_dir = optarg;
357 break;
358#ifdef CMDLINE_PROCESS
359 CMDLINE_PROCESS
360#endif
361 }
362
dc391246
UD
363 /* If set, read the test TIMEOUTFACTOR value from the environment.
364 This value is used to scale the default test timeout values. */
365 char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
366 if (envstr_timeoutfactor != NULL)
367 {
368 char *envstr_conv = envstr_timeoutfactor;
369 unsigned long int env_fact;
370
371 env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
372 if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
373 timeoutfactor = MAX (env_fact, 1);
374 }
375
80a18298
UD
376 /* Set TMPDIR to specified test directory. */
377 if (test_dir != NULL)
378 {
379 setenv ("TMPDIR", test_dir, 1);
380
381 if (chdir (test_dir) < 0)
382 {
c5c13355 383 printf ("chdir: %m\n");
80a18298
UD
384 exit (1);
385 }
386 }
b9337b6a
UD
387 else
388 {
389 test_dir = getenv ("TMPDIR");
390 if (test_dir == NULL || test_dir[0] == '\0')
391 test_dir = "/tmp";
392 }
80a18298 393
6b9c2e67
UD
394 /* Make sure we see all message, even those on stdout. */
395 setvbuf (stdout, NULL, _IONBF, 0);
396
b0b88abc 397 /* Make sure temporary files are deleted. */
310b3460
UD
398 atexit (delete_temp_files);
399
726b7b0f 400 /* Correct for the possible parameters. */
55033a44 401 argv[optind - 1] = argv[0];
726b7b0f
UD
402 argv += optind - 1;
403 argc -= optind - 1;
404
310b3460
UD
405 /* Call the initializing function, if one is available. */
406#ifdef PREPARE
407 PREPARE (argc, argv);
408#endif
409
b0b88abc
RM
410 const char *envstr_direct = getenv ("TEST_DIRECT");
411 if (envstr_direct != NULL)
412 {
413 FILE *f = fopen (envstr_direct, "w");
414 if (f == NULL)
415 {
416 printf ("cannot open TEST_DIRECT output file '%s': %m\n",
417 envstr_direct);
418 exit (1);
419 }
420
421 fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", TIMEOUT, timeoutfactor);
422#ifdef EXPECTED_STATUS
423 fprintf (f, "exit=%u\n", EXPECTED_STATUS);
424#endif
425#ifdef EXPECTED_SIGNAL
426 switch (EXPECTED_SIGNAL)
427 {
428 default: abort ();
429# define init_sig(signo, name, text) \
430 case signo: fprintf (f, "signal=%s\n", name); break;
431# include <siglist.h>
432# undef init_sig
433 }
434#endif
435
436 if (temp_name_list != NULL)
437 {
330fadfc 438 struct temp_name_list *n;
b0b88abc 439 fprintf (f, "temp_files=(\n");
330fadfc 440 for (n = temp_name_list;
b0b88abc
RM
441 n != NULL;
442 n = (struct temp_name_list *) n->q.q_forw)
443 fprintf (f, " '%s'\n", n->name);
444 fprintf (f, ")\n");
445 }
446
447 fclose (f);
448 direct = 1;
449 }
450
80a18298
UD
451 /* If we are not expected to fork run the function immediately. */
452 if (direct)
453 return TEST_FUNCTION;
454
455 /* Set up the test environment:
456 - prevent core dumps
457 - set up the timer
458 - fork and execute the function. */
459
460 pid = fork ();
461 if (pid == 0)
462 {
463 /* This is the child. */
464#ifdef RLIMIT_CORE
465 /* Try to avoid dumping core. */
466 struct rlimit core_limit;
467 core_limit.rlim_cur = 0;
468 core_limit.rlim_max = 0;
469 setrlimit (RLIMIT_CORE, &core_limit);
470#endif
63b11dd1 471
b79e3737
RM
472 /* We put the test process in its own pgrp so that if it bogusly
473 generates any job control signals, they won't hit the whole build. */
d7a05d07
MR
474 if (setpgid (0, 0) != 0)
475 printf ("Failed to set the process group ID: %m\n");
b79e3737 476
80a18298
UD
477 /* Execute the test function and exit with the return value. */
478 exit (TEST_FUNCTION);
479 }
480 else if (pid < 0)
481 {
c5c13355 482 printf ("Cannot fork test program: %m\n");
80a18298
UD
483 exit (1);
484 }
485
486 /* Set timeout. */
85fda49b 487 signal (SIGALRM, signal_handler);
dc391246 488 alarm (TIMEOUT * timeoutfactor);
80a18298 489
85fda49b
UD
490 /* Make sure we clean up if the wrapper gets interrupted. */
491 signal (SIGINT, signal_handler);
492
80a18298 493 /* Wait for the regular termination. */
53854476 494 termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
608c5afd 495 if (termpid == -1)
80a18298 496 {
608c5afd
UD
497 printf ("Waiting for test program failed: %m\n");
498 exit (1);
499 }
500 if (termpid != pid)
501 {
502 printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
503 (long int) pid, (long int) termpid);
80a18298
UD
504 exit (1);
505 }
506
fffa1cf8
LH
507 /* Process terminated normaly without timeout etc. */
508 if (WIFEXITED (status))
80a18298 509 {
ede0f73a 510#ifndef EXPECTED_STATUS
fffa1cf8
LH
511# ifndef EXPECTED_SIGNAL
512 /* Simply exit with the return value of the test. */
513 return WEXITSTATUS (status);
514# else
515 printf ("Expected signal '%s' from child, got none\n",
516 strsignal (EXPECTED_SIGNAL));
517 exit (1);
518# endif
ede0f73a 519#else
fffa1cf8
LH
520 if (WEXITSTATUS (status) != EXPECTED_STATUS)
521 {
522 printf ("Expected status %d, got %d\n",
523 EXPECTED_STATUS, WEXITSTATUS (status));
524 exit (1);
525 }
526
527 return 0;
528#endif
529 }
530 /* Process was killed by timer or other signal. */
531 else
ede0f73a 532 {
fffa1cf8
LH
533#ifndef EXPECTED_SIGNAL
534 printf ("Didn't expect signal from child: got `%s'\n",
535 strsignal (WTERMSIG (status)));
ede0f73a 536 exit (1);
fffa1cf8
LH
537#else
538 if (WTERMSIG (status) != EXPECTED_SIGNAL)
539 {
540 printf ("Incorrect signal from child: got `%s', need `%s'\n",
541 strsignal (WTERMSIG (status)),
542 strsignal (EXPECTED_SIGNAL));
543 exit (1);
544 }
ede0f73a 545
fffa1cf8 546 return 0;
ede0f73a 547#endif
fffa1cf8 548 }
80a18298 549}