test-skeleton: Support temporary files without memory leaks [BZ#18333]
[platform/upstream/glibc.git] / test-skeleton.c
1 /* Skeleton for test programs.
2    Copyright (C) 1998-2015 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 two seconds.  */
50 # define TIMEOUT 2
51 #endif
52
53 #define OPT_DIRECT 1000
54 #define OPT_TESTDIR 1001
55
56 static struct option options[] =
57 {
58 #ifdef CMDLINE_OPTIONS
59   CMDLINE_OPTIONS
60 #endif
61   { "direct", no_argument, NULL, OPT_DIRECT },
62   { "test-dir", required_argument, NULL, OPT_TESTDIR },
63   { NULL, 0, NULL, 0 }
64 };
65
66 /* PID of the test itself.  */
67 static pid_t pid;
68
69 /* Directory to place temporary files in.  */
70 static const char *test_dir;
71
72 /* List of temporary files.  */
73 struct temp_name_list
74 {
75   struct qelem q;
76   char *name;
77 } *temp_name_list;
78
79 /* Add temporary files in list.  */
80 static void
81 __attribute__ ((unused))
82 add_temp_file (const char *name)
83 {
84   struct temp_name_list *newp
85     = (struct temp_name_list *) calloc (sizeof (*newp), 1);
86   char *newname = strdup (name);
87   if (newp != NULL && newname != NULL)
88     {
89       newp->name = newname;
90       if (temp_name_list == NULL)
91         temp_name_list = (struct temp_name_list *) &newp->q;
92       else
93         insque (newp, temp_name_list);
94     }
95   else
96     free (newp);
97 }
98
99 /* Delete all temporary files.  */
100 static void
101 delete_temp_files (void)
102 {
103   while (temp_name_list != NULL)
104     {
105       remove (temp_name_list->name);
106       free (temp_name_list->name);
107
108       struct temp_name_list *next
109         = (struct temp_name_list *) temp_name_list->q.q_forw;
110       free (temp_name_list);
111       temp_name_list = next;
112     }
113 }
114
115 /* Create a temporary file.  Return the opened file descriptor on
116    success, or -1 on failure.  Write the file name to *FILENAME if
117    FILENAME is not NULL.  In this case, the caller is expected to free
118    *FILENAME.  */
119 static int
120 __attribute__ ((unused))
121 create_temp_file (const char *base, char **filename)
122 {
123   char *fname;
124   int fd;
125
126   fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base)
127                            + sizeof ("XXXXXX"));
128   if (fname == NULL)
129     {
130       puts ("out of memory");
131       return -1;
132     }
133   strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
134
135   fd = mkstemp (fname);
136   if (fd == -1)
137     {
138       printf ("cannot open temporary file '%s': %m\n", fname);
139       free (fname);
140       return -1;
141     }
142
143   add_temp_file (fname);
144   if (filename != NULL)
145     *filename = fname;
146   else
147     free (fname);
148
149   return fd;
150 }
151
152 /* Timeout handler.  We kill the child and exit with an error.  */
153 static void
154 __attribute__ ((noreturn))
155 signal_handler (int sig __attribute__ ((unused)))
156 {
157   int killed;
158   int status;
159
160   assert (pid > 1);
161   /* Kill the whole process group.  */
162   kill (-pid, SIGKILL);
163   /* In case setpgid failed in the child, kill it individually too.  */
164   kill (pid, SIGKILL);
165
166   /* Wait for it to terminate.  */
167   int i;
168   for (i = 0; i < 5; ++i)
169     {
170       killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
171       if (killed != 0)
172         break;
173
174       /* Delay, give the system time to process the kill.  If the
175          nanosleep() call return prematurely, all the better.  We
176          won't restart it since this probably means the child process
177          finally died.  */
178       struct timespec ts;
179       ts.tv_sec = 0;
180       ts.tv_nsec = 100000000;
181       nanosleep (&ts, NULL);
182     }
183   if (killed != 0 && killed != pid)
184     {
185       printf ("Failed to kill test process: %m\n");
186       exit (1);
187     }
188
189 #ifdef CLEANUP_HANDLER
190   CLEANUP_HANDLER;
191 #endif
192
193   if (sig == SIGINT)
194     {
195       signal (sig, SIG_DFL);
196       raise (sig);
197     }
198
199   /* If we expected this signal: good!  */
200 #ifdef EXPECTED_SIGNAL
201   if (EXPECTED_SIGNAL == SIGALRM)
202     exit (0);
203 #endif
204
205   if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
206     puts ("Timed out: killed the child process");
207   else if (WIFSTOPPED (status))
208     printf ("Timed out: the child process was %s\n",
209             strsignal (WSTOPSIG (status)));
210   else if (WIFSIGNALED (status))
211     printf ("Timed out: the child process got signal %s\n",
212             strsignal (WTERMSIG (status)));
213   else
214     printf ("Timed out: killed the child process but it exited %d\n",
215             WEXITSTATUS (status));
216
217   /* Exit with an error.  */
218   exit (1);
219 }
220
221 /* Set fortification error handler.  Used when tests want to verify that bad
222    code is caught by the library.  */
223 static void
224 __attribute__ ((unused))
225 set_fortify_handler (void (*handler) (int sig))
226 {
227   struct sigaction sa;
228
229   sa.sa_handler = handler;
230   sa.sa_flags = 0;
231   sigemptyset (&sa.sa_mask);
232
233   sigaction (SIGABRT, &sa, NULL);
234
235   /* Avoid all the buffer overflow messages on stderr.  */
236   int fd = open (_PATH_DEVNULL, O_WRONLY);
237   if (fd == -1)
238     close (STDERR_FILENO);
239   else
240     {
241       dup2 (fd, STDERR_FILENO);
242       close (fd);
243     }
244   setenv ("LIBC_FATAL_STDERR_", "1", 1);
245 }
246
247 /* We provide the entry point here.  */
248 int
249 main (int argc, char *argv[])
250 {
251   int direct = 0;       /* Directly call the test function?  */
252   int status;
253   int opt;
254   unsigned int timeoutfactor = 1;
255   pid_t termpid;
256
257   /* Make uses of freed and uninitialized memory known.  */
258   mallopt (M_PERTURB, 42);
259
260 #ifdef STDOUT_UNBUFFERED
261   setbuf (stdout, NULL);
262 #endif
263
264   while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
265     switch (opt)
266       {
267       case '?':
268         exit (1);
269       case OPT_DIRECT:
270         direct = 1;
271         break;
272       case OPT_TESTDIR:
273         test_dir = optarg;
274         break;
275 #ifdef CMDLINE_PROCESS
276         CMDLINE_PROCESS
277 #endif
278       }
279
280   /* If set, read the test TIMEOUTFACTOR value from the environment.
281      This value is used to scale the default test timeout values. */
282   char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
283   if (envstr_timeoutfactor != NULL)
284     {
285       char *envstr_conv = envstr_timeoutfactor;
286       unsigned long int env_fact;
287
288       env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
289       if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
290         timeoutfactor = MAX (env_fact, 1);
291     }
292
293   /* Set TMPDIR to specified test directory.  */
294   if (test_dir != NULL)
295     {
296       setenv ("TMPDIR", test_dir, 1);
297
298       if (chdir (test_dir) < 0)
299         {
300           printf ("chdir: %m\n");
301           exit (1);
302         }
303     }
304   else
305     {
306       test_dir = getenv ("TMPDIR");
307       if (test_dir == NULL || test_dir[0] == '\0')
308         test_dir = "/tmp";
309     }
310
311   /* Make sure we see all message, even those on stdout.  */
312   setvbuf (stdout, NULL, _IONBF, 0);
313
314   /* Make sure temporary files are deleted.  */
315   atexit (delete_temp_files);
316
317   /* Correct for the possible parameters.  */
318   argv[optind - 1] = argv[0];
319   argv += optind - 1;
320   argc -= optind - 1;
321
322   /* Call the initializing function, if one is available.  */
323 #ifdef PREPARE
324   PREPARE (argc, argv);
325 #endif
326
327   const char *envstr_direct = getenv ("TEST_DIRECT");
328   if (envstr_direct != NULL)
329     {
330       FILE *f = fopen (envstr_direct, "w");
331       if (f == NULL)
332         {
333           printf ("cannot open TEST_DIRECT output file '%s': %m\n",
334                   envstr_direct);
335           exit (1);
336         }
337
338       fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", TIMEOUT, timeoutfactor);
339 #ifdef EXPECTED_STATUS
340       fprintf (f, "exit=%u\n", EXPECTED_STATUS);
341 #endif
342 #ifdef EXPECTED_SIGNAL
343       switch (EXPECTED_SIGNAL)
344         {
345         default: abort ();
346 # define init_sig(signo, name, text) \
347         case signo: fprintf (f, "signal=%s\n", name); break;
348 # include <siglist.h>
349 # undef init_sig
350         }
351 #endif
352
353       if (temp_name_list != NULL)
354         {
355           fprintf (f, "temp_files=(\n");
356           for (struct temp_name_list *n = temp_name_list;
357                n != NULL;
358                n = (struct temp_name_list *) n->q.q_forw)
359             fprintf (f, "  '%s'\n", n->name);
360           fprintf (f, ")\n");
361         }
362
363       fclose (f);
364       direct = 1;
365     }
366
367   /* If we are not expected to fork run the function immediately.  */
368   if (direct)
369     return TEST_FUNCTION;
370
371   /* Set up the test environment:
372      - prevent core dumps
373      - set up the timer
374      - fork and execute the function.  */
375
376   pid = fork ();
377   if (pid == 0)
378     {
379       /* This is the child.  */
380 #ifdef RLIMIT_CORE
381       /* Try to avoid dumping core.  */
382       struct rlimit core_limit;
383       core_limit.rlim_cur = 0;
384       core_limit.rlim_max = 0;
385       setrlimit (RLIMIT_CORE, &core_limit);
386 #endif
387
388 #ifdef RLIMIT_DATA
389       /* Try to avoid eating all memory if a test leaks.  */
390       struct rlimit data_limit;
391       if (getrlimit (RLIMIT_DATA, &data_limit) == 0)
392         {
393           if (TEST_DATA_LIMIT == RLIM_INFINITY)
394             data_limit.rlim_cur = data_limit.rlim_max;
395           else if (data_limit.rlim_cur > (rlim_t) TEST_DATA_LIMIT)
396             data_limit.rlim_cur = MIN ((rlim_t) TEST_DATA_LIMIT,
397                                        data_limit.rlim_max);
398           if (setrlimit (RLIMIT_DATA, &data_limit) < 0)
399             printf ("setrlimit: RLIMIT_DATA: %m\n");
400         }
401       else
402         printf ("getrlimit: RLIMIT_DATA: %m\n");
403 #endif
404
405       /* We put the test process in its own pgrp so that if it bogusly
406          generates any job control signals, they won't hit the whole build.  */
407       if (setpgid (0, 0) != 0)
408         printf ("Failed to set the process group ID: %m\n");
409
410       /* Execute the test function and exit with the return value.   */
411       exit (TEST_FUNCTION);
412     }
413   else if (pid < 0)
414     {
415       printf ("Cannot fork test program: %m\n");
416       exit (1);
417     }
418
419   /* Set timeout.  */
420   signal (SIGALRM, signal_handler);
421   alarm (TIMEOUT * timeoutfactor);
422
423   /* Make sure we clean up if the wrapper gets interrupted.  */
424   signal (SIGINT, signal_handler);
425
426   /* Wait for the regular termination.  */
427   termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
428   if (termpid == -1)
429     {
430       printf ("Waiting for test program failed: %m\n");
431       exit (1);
432     }
433   if (termpid != pid)
434     {
435       printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
436               (long int) pid, (long int) termpid);
437       exit (1);
438     }
439
440   /* Process terminated normaly without timeout etc.  */
441   if (WIFEXITED (status))
442     {
443 #ifndef EXPECTED_STATUS
444 # ifndef EXPECTED_SIGNAL
445       /* Simply exit with the return value of the test.  */
446       return WEXITSTATUS (status);
447 # else
448       printf ("Expected signal '%s' from child, got none\n",
449               strsignal (EXPECTED_SIGNAL));
450       exit (1);
451 # endif
452 #else
453       if (WEXITSTATUS (status) != EXPECTED_STATUS)
454         {
455           printf ("Expected status %d, got %d\n",
456                   EXPECTED_STATUS, WEXITSTATUS (status));
457           exit (1);
458         }
459
460       return 0;
461 #endif
462     }
463   /* Process was killed by timer or other signal.  */
464   else
465     {
466 #ifndef EXPECTED_SIGNAL
467       printf ("Didn't expect signal from child: got `%s'\n",
468               strsignal (WTERMSIG (status)));
469       exit (1);
470 #else
471       if (WTERMSIG (status) != EXPECTED_SIGNAL)
472         {
473           printf ("Incorrect signal from child: got `%s', need `%s'\n",
474                   strsignal (WTERMSIG (status)),
475                   strsignal (EXPECTED_SIGNAL));
476           exit (1);
477         }
478
479       return 0;
480 #endif
481     }
482 }