]> git.ipfire.org Git - thirdparty/glibc.git/blob - test-skeleton.c
2016-06-09 Paul Pluzhnikov <ppluzhnikov@gmail.com>
[thirdparty/glibc.git] / test-skeleton.c
1 /* Skeleton for test programs.
2 Copyright (C) 1998-2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <malloc.h>
25 #include <paths.h>
26 #include <search.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/resource.h>
33 #include <sys/wait.h>
34 #include <sys/param.h>
35 #include <time.h>
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
44 #ifndef TEST_DATA_LIMIT
45 # define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with. */
46 #endif
47
48 #ifndef TIMEOUT
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
52 #endif
53
54 #define OPT_DIRECT 1000
55 #define OPT_TESTDIR 1001
56
57 static 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. */
68 static pid_t pid;
69
70 /* Directory to place temporary files in. */
71 static const char *test_dir;
72
73 static void
74 oom_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. */
81 static void *
82 __attribute__ ((used))
83 xmalloc (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. */
94 static void *
95 __attribute__ ((used))
96 xcalloc (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. */
108 static void *
109 __attribute__ ((used))
110 xrealloc (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
118 /* List of temporary files. */
119 struct temp_name_list
120 {
121 struct qelem q;
122 char *name;
123 } *temp_name_list;
124
125 /* Add temporary files in list. */
126 static void
127 __attribute__ ((unused))
128 add_temp_file (const char *name)
129 {
130 struct temp_name_list *newp
131 = (struct temp_name_list *) xcalloc (sizeof (*newp), 1);
132 char *newname = strdup (name);
133 if (newname != NULL)
134 {
135 newp->name = newname;
136 if (temp_name_list == NULL)
137 temp_name_list = (struct temp_name_list *) &newp->q;
138 else
139 insque (newp, temp_name_list);
140 }
141 else
142 free (newp);
143 }
144
145 /* Delete all temporary files. */
146 static void
147 delete_temp_files (void)
148 {
149 while (temp_name_list != NULL)
150 {
151 remove (temp_name_list->name);
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;
158 }
159 }
160
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. */
165 static int
166 __attribute__ ((unused))
167 create_temp_file (const char *base, char **filename)
168 {
169 char *fname;
170 int fd;
171
172 fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base)
173 + sizeof ("XXXXXX"));
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;
187 else
188 free (fname);
189
190 return fd;
191 }
192
193 /* Timeout handler. We kill the child and exit with an error. */
194 static void
195 __attribute__ ((noreturn))
196 signal_handler (int sig __attribute__ ((unused)))
197 {
198 int killed;
199 int status;
200
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. */
205 kill (pid, SIGKILL);
206
207 /* Wait for it to terminate. */
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. */
219 struct timespec ts;
220 ts.tv_sec = 0;
221 ts.tv_nsec = 100000000;
222 nanosleep (&ts, NULL);
223 }
224 if (killed != 0 && killed != pid)
225 {
226 printf ("Failed to kill test process: %m\n");
227 exit (1);
228 }
229
230 #ifdef CLEANUP_HANDLER
231 CLEANUP_HANDLER;
232 #endif
233
234 if (sig == SIGINT)
235 {
236 signal (sig, SIG_DFL);
237 raise (sig);
238 }
239
240 /* If we expected this signal: good! */
241 #ifdef EXPECTED_SIGNAL
242 if (EXPECTED_SIGNAL == SIGALRM)
243 exit (0);
244 #endif
245
246 if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
247 puts ("Timed out: killed the child process");
248 else if (WIFSTOPPED (status))
249 printf ("Timed out: the child process was %s\n",
250 strsignal (WSTOPSIG (status)));
251 else if (WIFSIGNALED (status))
252 printf ("Timed out: the child process got signal %s\n",
253 strsignal (WTERMSIG (status)));
254 else
255 printf ("Timed out: killed the child process but it exited %d\n",
256 WEXITSTATUS (status));
257
258 /* Exit with an error. */
259 exit (1);
260 }
261
262 /* Avoid all the buffer overflow messages on stderr. */
263 static void
264 __attribute__ ((unused))
265 ignore_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
278 /* Set fortification error handler. Used when tests want to verify that bad
279 code is caught by the library. */
280 static void
281 __attribute__ ((unused))
282 set_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);
291 ignore_stderr ();
292 }
293
294 /* Show people how to run the program. */
295 static void
296 usage (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
329 /* We provide the entry point here. */
330 int
331 main (int argc, char *argv[])
332 {
333 int direct = 0; /* Directly call the test function? */
334 int status;
335 int opt;
336 unsigned int timeoutfactor = 1;
337 pid_t termpid;
338
339 /* Make uses of freed and uninitialized memory known. */
340 mallopt (M_PERTURB, 42);
341
342 #ifdef STDOUT_UNBUFFERED
343 setbuf (stdout, NULL);
344 #endif
345
346 while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
347 switch (opt)
348 {
349 case '?':
350 usage ();
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
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
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 {
383 printf ("chdir: %m\n");
384 exit (1);
385 }
386 }
387 else
388 {
389 test_dir = getenv ("TMPDIR");
390 if (test_dir == NULL || test_dir[0] == '\0')
391 test_dir = "/tmp";
392 }
393
394 /* Make sure we see all message, even those on stdout. */
395 setvbuf (stdout, NULL, _IONBF, 0);
396
397 /* Make sure temporary files are deleted. */
398 atexit (delete_temp_files);
399
400 /* Correct for the possible parameters. */
401 argv[optind - 1] = argv[0];
402 argv += optind - 1;
403 argc -= optind - 1;
404
405 /* Call the initializing function, if one is available. */
406 #ifdef PREPARE
407 PREPARE (argc, argv);
408 #endif
409
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 {
438 struct temp_name_list *n;
439 fprintf (f, "temp_files=(\n");
440 for (n = temp_name_list;
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
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
471
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. */
474 if (setpgid (0, 0) != 0)
475 printf ("Failed to set the process group ID: %m\n");
476
477 /* Execute the test function and exit with the return value. */
478 exit (TEST_FUNCTION);
479 }
480 else if (pid < 0)
481 {
482 printf ("Cannot fork test program: %m\n");
483 exit (1);
484 }
485
486 /* Set timeout. */
487 signal (SIGALRM, signal_handler);
488 alarm (TIMEOUT * timeoutfactor);
489
490 /* Make sure we clean up if the wrapper gets interrupted. */
491 signal (SIGINT, signal_handler);
492
493 /* Wait for the regular termination. */
494 termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
495 if (termpid == -1)
496 {
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);
504 exit (1);
505 }
506
507 /* Process terminated normaly without timeout etc. */
508 if (WIFEXITED (status))
509 {
510 #ifndef EXPECTED_STATUS
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
519 #else
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
532 {
533 #ifndef EXPECTED_SIGNAL
534 printf ("Didn't expect signal from child: got `%s'\n",
535 strsignal (WTERMSIG (status)));
536 exit (1);
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 }
545
546 return 0;
547 #endif
548 }
549 }