Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
glibc
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Security
Insights
Files
2d094b7
abilist
aout
argp
assert
bits
catgets
conf
conform
crypt
csu
ctype
debug
dirent
dlfcn
elf
gmon
gnulib
grp
gshadow
hesiod
hurd
iconv
iconvdata
include
inet
intl
io
libidn
libio
locale
localedata
login
mach
malloc
manual
math
misc
nis
nptl
nptl_db
nscd
nss
po
posix
pwd
resolv
resource
rt
scripts
setjmp
shadow
signal
socket
soft-fp
stdio-common
stdlib
streams
string
sunrpc
sysdeps
sysvipc
termios
time
timezone
wcsmbs
wctype
.gitattributes
.gitignore
BUGS
CANCEL-FCT-WAIVE
CANCEL-FILE-WAIVE
CONFORMANCE
COPYING
COPYING.LIB
ChangeLog
ChangeLog.1
ChangeLog.10
ChangeLog.11
ChangeLog.12
ChangeLog.13
ChangeLog.14
ChangeLog.15
ChangeLog.16
ChangeLog.2
ChangeLog.3
ChangeLog.4
ChangeLog.5
ChangeLog.6
ChangeLog.7
ChangeLog.8
ChangeLog.9
FAQ
FAQ.in
INSTALL
LICENSES
Makeconfig
Makefile
Makefile.in
Makerules
NAMESPACE
NEWS
NOTES
PROJECTS
README
README.libm
Rules
Versions.def
WUR-REPORT
abi-tags
aclocal.m4
config-name.in
config.h.in
config.make.in
configure
configure.in
cppflags-iterator.mk
extra-lib.mk
extra-modules.mk
o-iterator.mk
shlib-versions
test-skeleton.c
tls.make.c
version.h
Breadcrumbs
glibc
/
test-skeleton.c
Blame
Blame
Latest commit
History
History
391 lines (340 loc) · 9.68 KB
Breadcrumbs
glibc
/
test-skeleton.c
Top
File metadata and controls
Code
Blame
391 lines (340 loc) · 9.68 KB
Raw
/* Skeleton for test programs. Copyright (C) 1998,2000-2004, 2005, 2009 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include <errno.h> #include <getopt.h> #include <malloc.h> #include <search.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/resource.h> #include <sys/wait.h> #include <sys/param.h> #include <time.h> /* The test function is normally called `do_test' and it is called with argc and argv as the arguments. We nevertheless provide the possibility to overwrite this name. */ #ifndef TEST_FUNCTION # define TEST_FUNCTION do_test (argc, argv) #endif #ifndef TEST_DATA_LIMIT # define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with. */ #endif #define OPT_DIRECT 1000 #define OPT_TESTDIR 1001 static struct option options[] = { #ifdef CMDLINE_OPTIONS CMDLINE_OPTIONS #endif { "direct", no_argument, NULL, OPT_DIRECT }, { "test-dir", required_argument, NULL, OPT_TESTDIR }, { NULL, 0, NULL, 0 } }; /* PID of the test itself. */ static pid_t pid; /* Directory to place temporary files in. */ static const char *test_dir; /* List of temporary files. */ struct temp_name_list { struct qelem q; const char *name; } *temp_name_list; /* Add temporary files in list. */ static void __attribute__ ((unused)) add_temp_file (const char *name) { struct temp_name_list *newp = (struct temp_name_list *) calloc (sizeof (*newp), 1); if (newp != NULL) { newp->name = name; if (temp_name_list == NULL) temp_name_list = (struct temp_name_list *) &newp->q; else insque (newp, temp_name_list); } } /* Delete all temporary files. */ static void delete_temp_files (void) { while (temp_name_list != NULL) { remove (temp_name_list->name); temp_name_list = (struct temp_name_list *) temp_name_list->q.q_forw; } } /* Create a temporary file. */ static int __attribute__ ((unused)) create_temp_file (const char *base, char **filename) { char *fname; int fd; fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base) + sizeof ("XXXXXX")); if (fname == NULL) { puts ("out of memory"); return -1; } strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); fd = mkstemp (fname); if (fd == -1) { printf ("cannot open temporary file '%s': %m\n", fname); free (fname); return -1; } add_temp_file (fname); if (filename != NULL) *filename = fname; return fd; } /* Timeout handler. We kill the child and exit with an error. */ static void __attribute__ ((noreturn)) signal_handler (int sig __attribute__ ((unused))) { int killed; int status; /* Send signal. */ kill (pid, SIGKILL); /* Wait for it to terminate. */ int i; for (i = 0; i < 5; ++i) { killed = waitpid (pid, &status, WNOHANG|WUNTRACED); if (killed != 0) break; /* Delay, give the system time to process the kill. If the nanosleep() call return prematurely, all the better. We won't restart it since this probably means the child process finally died. */ struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000000; nanosleep (&ts, NULL); } if (killed != 0 && killed != pid) { perror ("Failed to kill test process"); exit (1); } #ifdef CLEANUP_HANDLER CLEANUP_HANDLER; #endif if (sig == SIGINT) { signal (sig, SIG_DFL); raise (sig); } /* If we expected this signal: good! */ #ifdef EXPECTED_SIGNAL if (EXPECTED_SIGNAL == SIGALRM) exit (0); #endif if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) fputs ("Timed out: killed the child process\n", stderr); else if (WIFSTOPPED (status)) fprintf (stderr, "Timed out: the child process was %s\n", strsignal (WSTOPSIG (status))); else if (WIFSIGNALED (status)) fprintf (stderr, "Timed out: the child process got signal %s\n", strsignal (WTERMSIG (status))); else fprintf (stderr, "Timed out: killed the child process but it exited %d\n", WEXITSTATUS (status)); /* Exit with an error. */ exit (1); } /* We provide the entry point here. */ int main (int argc, char *argv[]) { int direct = 0; /* Directly call the test function? */ int status; int opt; unsigned int timeoutfactor = 1; pid_t termpid; /* Make uses of freed and uninitialized memory known. */ mallopt (M_PERTURB, 42); #ifdef STDOUT_UNBUFFERED setbuf (stdout, NULL); #endif while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) switch (opt) { case '?': exit (1); case OPT_DIRECT: direct = 1; break; case OPT_TESTDIR: test_dir = optarg; break; #ifdef CMDLINE_PROCESS CMDLINE_PROCESS #endif } /* If set, read the test TIMEOUTFACTOR value from the environment. This value is used to scale the default test timeout values. */ char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR"); if (envstr_timeoutfactor != NULL) { char *envstr_conv = envstr_timeoutfactor; unsigned long int env_fact; env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) timeoutfactor = MAX (env_fact, 1); } /* Set TMPDIR to specified test directory. */ if (test_dir != NULL) { setenv ("TMPDIR", test_dir, 1); if (chdir (test_dir) < 0) { perror ("chdir"); exit (1); } } else { test_dir = getenv ("TMPDIR"); if (test_dir == NULL || test_dir[0] == '\0') test_dir = "/tmp"; } /* Make sure we see all message, even those on stdout. */ setvbuf (stdout, NULL, _IONBF, 0); /* make sure temporary files are deleted. */ atexit (delete_temp_files); /* Correct for the possible parameters. */ argv[optind - 1] = argv[0]; argv += optind - 1; argc -= optind - 1; /* Call the initializing function, if one is available. */ #ifdef PREPARE PREPARE (argc, argv); #endif /* If we are not expected to fork run the function immediately. */ if (direct) return TEST_FUNCTION; /* Set up the test environment: - prevent core dumps - set up the timer - fork and execute the function. */ pid = fork (); if (pid == 0) { /* This is the child. */ #ifdef RLIMIT_CORE /* Try to avoid dumping core. */ struct rlimit core_limit; core_limit.rlim_cur = 0; core_limit.rlim_max = 0; setrlimit (RLIMIT_CORE, &core_limit); #endif #ifdef RLIMIT_DATA /* Try to avoid eating all memory if a test leaks. */ struct rlimit data_limit; if (getrlimit (RLIMIT_DATA, &data_limit) == 0) { if (TEST_DATA_LIMIT == RLIM_INFINITY) data_limit.rlim_cur = data_limit.rlim_max; else if (data_limit.rlim_cur > (rlim_t) TEST_DATA_LIMIT) data_limit.rlim_cur = MIN ((rlim_t) TEST_DATA_LIMIT, data_limit.rlim_max); if (setrlimit (RLIMIT_DATA, &data_limit) < 0) perror ("setrlimit: RLIMIT_DATA"); } else perror ("getrlimit: RLIMIT_DATA"); #endif /* We put the test process in its own pgrp so that if it bogusly generates any job control signals, they won't hit the whole build. */ setpgid (0, 0); /* Execute the test function and exit with the return value. */ exit (TEST_FUNCTION); } else if (pid < 0) { perror ("Cannot fork test program"); exit (1); } /* Set timeout. */ #ifndef TIMEOUT /* Default timeout is two seconds. */ # define TIMEOUT 2 #endif signal (SIGALRM, signal_handler); alarm (TIMEOUT * timeoutfactor); /* Make sure we clean up if the wrapper gets interrupted. */ signal (SIGINT, signal_handler); /* Wait for the regular termination. */ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); if (termpid == -1) { printf ("Waiting for test program failed: %m\n"); exit (1); } if (termpid != pid) { printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", (long int) pid, (long int) termpid); exit (1); } #ifndef EXPECTED_SIGNAL /* We don't expect any signal. */ # define EXPECTED_SIGNAL 0 #endif if (WTERMSIG (status) != EXPECTED_SIGNAL) { if (EXPECTED_SIGNAL != 0) { if (WTERMSIG (status) == 0) fprintf (stderr, "Expected signal '%s' from child, got none\n", strsignal (EXPECTED_SIGNAL)); else fprintf (stderr, "Incorrect signal from child: got `%s', need `%s'\n", strsignal (WTERMSIG (status)), strsignal (EXPECTED_SIGNAL)); } else fprintf (stderr, "Didn't expect signal from child: got `%s'\n", strsignal (WTERMSIG (status))); exit (1); } /* Simply exit with the return value of the test. */ #ifndef EXPECTED_STATUS return WEXITSTATUS (status); #else if (WEXITSTATUS (status) != EXPECTED_STATUS) { fprintf (stderr, "Expected status %d, got %d\n", EXPECTED_STATUS, WEXITSTATUS (status)); exit (1); } return 0; #endif }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
You can’t perform that action at this time.