1 /* Check system header files for ISO 9899:1990 (ISO C) compliance.
2 Copyright (C) 1996-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* This is a simple minded program that tries to find illegal macro
20 definitions in system header files. Illegal macro definitions are
21 those not from the implementation namespace (i.e. not starting with
22 an underscore) or not matching any identifier mandated by The
23 Standard. Some common macro names are considered okay, e.g. all those
24 beginning with E (which may be defined in <errno.h>) or ending in
25 _MAX. See the arrays prefix[] and suffix[] below for details.
27 In a compliant implementation no other macros can be defined, because
28 you could write strictly conforming programs that may fail to compile
29 due to syntax errors: suppose <stdio.h> defines PIPE_BUF, then the
33 #include <stdio.h> <- or where the bogus macro is defined
36 #define XSTR(x) STR(x)
40 assert (strcmp ("PIPE_BUF", XSTR (PIPE_BUF)) == 0);
44 is expected to compile and meet the assertion. If it does not, your
45 compiler compiles some other language than Standard C.
48 This program calls ${1-gcc} to get the list of defined macros. If you
49 don't have gcc you're probably out of luck unless your compiler or
50 preprocessor has something similar to gcc's -dM option. This program
51 assumes headers are found in the default search path (pass -I... in
52 $2 if this is not the case) and that there is a writable /tmp directory.
55 Each header file name is printed, followed by illegal macro names
56 and their definition. For the above example, you would see
61 If your implementation does not yet incorporate Amendment 1 you
62 will see messages about iso646.h, wctype.h and wchar.h not being
66 # define _GNU_SOURCE 1
75 #define HEADER_MAX 256
77 static char macrofile
[] = "/tmp/isomac.XXXXXX";
79 /* ISO C header names including Amendment 1 (without ".h" suffix). */
80 static char *header
[] =
82 "assert", "ctype", "errno", "float", "iso646", "limits", "locale",
83 "math", "setjmp", "signal", "stdarg", "stddef", "stdio", "stdlib",
84 "string", "time", "wchar", "wctype"
87 /* Macros with these prefixes are considered okay. */
88 static char *prefix
[] =
90 "_", "E", "is", "str", "mem", "SIG", "FLT_", "DBL_", "LDBL_",
94 /* Macros with these suffixes are considered okay. Will not work for
95 parametrized macros with arguments. */
96 static char *suffix
[] =
101 /* These macros are considered okay. In fact, these are just more prefixes. */
102 static char *macros
[] =
104 "BUFSIZ", "CHAR_BIT", "CHAR_MAX", "CHAR_MIN", "CLOCKS_PER_SEC",
105 "DBL_DIG", "DBL_EPSILON", "DBL_MANT_DIG", "DBL_MAX",
106 "DBL_MAX_10_EXP", "DBL_MAX_EXP", "DBL_MIN", "DBL_MIN_10_EXP",
107 "DBL_MIN_EXP", "EDOM", "EILSEQ", "EOF", "ERANGE", "EXIT_FAILURE",
108 "EXIT_SUCCESS", "FILENAME_MAX", "FLT_DIG", "FLT_EPSILON",
109 "FLT_MANT_DIG", "FLT_MAX", "FLT_MAX_10_EXP", "FLT_MAX_EXP",
110 "FLT_MIN", "FLT_MIN_10_EXP", "FLT_MIN_EXP", "FLT_RADIX",
111 "FLT_ROUNDS", "FOPEN_MAX", "HUGE_VAL", "INT_MAX", "INT_MIN",
112 "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC",
113 "LC_TIME", "LDBL_DIG", "LDBL_EPSILON", "LDBL_MANT_DIG", "LDBL_MAX",
114 "LDBL_MAX_10_EXP", "LDBL_MAX_EXP", "LDBL_MIN", "LDBL_MIN_10_EXP",
115 "LDBL_MIN_EXP", "LONG_MAX", "LONG_MIN", "L_tmpnam", "MB_CUR_MAX",
116 "MB_LEN_MAX", "NDEBUG", "NULL", "RAND_MAX", "SCHAR_MAX",
117 "SCHAR_MIN", "SEEK_CUR", "SEEK_END", "SEEK_SET", "SHRT_MAX",
118 "SHRT_MIN", "SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV",
119 "SIGTERM", "SIG_DFL", "SIG_ERR", "SIG_IGN", "TMP_MAX", "UCHAR_MAX",
120 "UINT_MAX", "ULONG_MAX", "USHRT_MAX", "WCHAR_MAX", "WCHAR_MIN",
121 "WEOF", "_IOFBF", "_IOLBF", "_IONBF", "abort", "abs", "acos",
122 "acosf", "acosl", "and", "and_eq", "asctime", "asin", "asinf",
123 "asinl", "assert", "atan", "atan2", "atan2f", "atan2l", "atanf",
124 "atanl", "atexit", "atof", "atoi", "atol", "bitand", "bitor",
125 "bsearch", "btowc", "calloc", "ceil", "ceilf", "ceill", "clearerr",
126 "clock", "clock_t", "compl", "cos", "cosf", "cosh", "coshf",
127 "coshl", "cosl", "ctime", "difftime", "div", "div_t", "errno",
128 "exit", "exp", "expf", "expl", "fabs", "fabsf", "fabsl", "fclose",
129 "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets", "fgetwc",
130 "fgetws", "floor", "floorf", "floorl", "fmod", "fmodf", "fmodl",
131 "fopen", "fprintf", "fputc", "fputs", "fputwc", "fputws", "fread",
132 "free", "freopen", "frexp", "frexpf", "frexpl", "fscanf", "fseek",
133 "fsetpos", "ftell", "fwide", "fwprintf", "fwrite", "fwscanf",
134 "getc", "getchar", "getenv", "gets", "getwc", "getwchar", "gmtime",
135 "isalnum", "isalpha", "iscntrl", "isdigit", "isgraph", "islower",
136 "isprint", "ispunct", "isspace", "isupper", "iswalnum", "iswalpha",
137 "iswcntrl", "iswctype", "iswdigit", "iswgraph", "iswlower",
138 "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit",
139 "isxdigit", "labs", "ldexp", "ldexpf", "ldexpl", "ldiv", "ldiv_t",
140 "localeconv", "localtime", "log", "log10", "log10f", "log10l",
141 "logf", "logl", "longjmp", "malloc", "mblen", "mbrlen", "mbrtowc",
142 "mbsinit", "mbsrtowcs", "mbstate_t", "mbstowcs", "mbtowc", "memchr",
143 "memcmp", "memcpy", "memmove", "memset", "mktime", "modf", "modff",
144 "modfl", "not", "not_eq", "offsetof", "or", "or_eq", "perror",
145 "pow", "powf", "powl", "printf", "ptrdiff_t", "putc", "putchar",
146 "puts", "putwc", "putwchar", "qsort", "raise", "rand", "realloc",
147 "remove", "rename", "rewind", "scanf", "setbuf", "setjmp",
148 "setlocale", "setvbuf", "sig_atomic_t", "signal", "sin", "sinf",
149 "sinh", "sinhf", "sinhl", "sinl", "size_t", "sprintf", "sqrt",
150 "sqrtf", "sqrtl", "srand", "sscanf", "stderr", "stdin", "stdout",
151 "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn",
152 "strerror", "strftime", "strlen", "strncat", "strncmp", "strncpy",
153 "strpbrk", "strrchr", "strspn", "strstr", "strtod", "strtok",
154 "strtol", "strtoul", "strxfrm", "swprintf", "swscanf", "system",
155 "tan", "tanf", "tanh", "tanhf", "tanhl", "tanl", "time", "time_t",
156 "tmpfile", "tmpnam", "tolower", "toupper", "towctrans", "towlower",
157 "towupper", "ungetc", "ungetwc", "va_arg", "va_copy", "va_end", "va_start",
158 "vfprintf", "vfwprintf", "vprintf", "vsprintf", "vswprintf",
159 "vwprintf", "wchar_t", "wcrtomb", "wcscat", "wcschr", "wcscmp",
160 "wcscoll", "wcscpy", "wcscspn", "wcsftime", "wcslen", "wcsncat",
161 "wcsncmp", "wcsncpy", "wcspbrk", "wcsrchr", "wcsrtombs", "wcsspn",
162 "wcsstr", "wcstod", "wcstok", "wcstol", "wcstombs", "wcstoul",
163 "wcsxfrm", "wctob", "wctomb", "wctrans", "wctrans_t", "wctype",
164 "wctype_t", "wint_t", "wmemchr", "wmemcmp", "wmemcpy", "wmemmove",
165 "wmemset", "wprintf", "wscanf", "xor", "xor_eq"
168 #define NUMBER_OF_HEADERS (sizeof header / sizeof *header)
169 #define NUMBER_OF_PREFIXES (sizeof prefix / sizeof *prefix)
170 #define NUMBER_OF_SUFFIXES (sizeof suffix / sizeof *suffix)
171 #define NUMBER_OF_MACROS (sizeof macros / sizeof *macros)
174 /* Format string to build command to invoke compiler. */
175 static const char fmt
[] = "\
176 echo \"#include <%s>\" |\
177 %s -E -dM -ansi -pedantic %s -D_LIBC -D_ISOMAC \
178 -DIN_MODULE=MODULE_extramodules -I. \
179 -isystem `%s --print-prog-name=include` - 2> /dev/null > %s";
182 /* The compiler we use (given on the command line). */
184 /* The -I parameters for CC to find all headers. */
187 static char *xstrndup (const char *, size_t);
188 static const char **get_null_defines (void);
189 static int check_header (const char *, const char **);
192 main (int argc
, char *argv
[])
196 const char **ignore_list
;
198 CC
= argc
> 1 ? argv
[1] : "gcc";
199 INC
= argc
> 2 ? argv
[2] : "";
201 if (system (NULL
) == 0)
203 puts ("Sorry, no command processor.");
207 /* First get list of symbols which are defined by the compiler. */
208 ignore_list
= get_null_defines ();
210 fputs ("Tested files:\n", stdout
);
212 for (h
= 0; h
< NUMBER_OF_HEADERS
; ++h
)
214 char file_name
[HEADER_MAX
];
215 sprintf (file_name
, "%s.h", header
[h
]);
216 result
|= check_header (file_name
, ignore_list
);
221 /* The test suite should return errors but for now this is not
222 practical. Give a warning and ask the user to correct the bugs. */
228 xstrndup (const char *s
, size_t n
)
231 char *new = malloc (len
+ 1);
237 return memcpy (new, s
, len
);
242 get_null_defines (void)
244 char line
[BUFSIZ
], *command
;
245 char **result
= NULL
;
246 size_t result_len
= 0;
247 size_t result_max
= 0;
251 int fd
= mkstemp (macrofile
);
254 printf ("mkstemp failed: %m\n");
259 command
= malloc (sizeof fmt
+ sizeof "/dev/null" + 2 * strlen (CC
)
260 + strlen (INC
) + strlen (macrofile
));
264 puts ("No more memory.");
268 sprintf (command
, fmt
, "/dev/null", CC
, INC
, CC
, macrofile
);
270 if (system (command
))
272 puts ("system() returned nonzero");
277 input
= fopen (macrofile
, "r");
281 printf ("Could not read %s: ", macrofile
);
286 while (fgets (line
, sizeof line
, input
) != NULL
)
291 if (strlen (line
) < 9 || line
[7] != ' ')
293 printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
298 /* It's a safe identifier. */
300 if (result_len
== result_max
)
303 result
= realloc (result
, result_max
* sizeof (char **));
306 puts ("No more memory.");
311 for (end
= start
+ 1; !isspace (*end
) && *end
!= '\0'; ++end
)
313 result
[result_len
] = xstrndup (start
, end
- start
);
315 if (strcmp (result
[result_len
], "IN_MODULE") != 0)
319 fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout
);
322 puts (result
[result_len
]);
326 if (result_len
== result_max
)
329 result
= realloc (result
, result_max
* sizeof (char **));
332 puts ("No more memory.");
336 result
[result_len
] = NULL
;
339 return (const char **) result
;
344 check_header (const char *file_name
, const char **except
)
346 char line
[BUFSIZ
], *command
;
350 command
= malloc (sizeof fmt
+ strlen (file_name
) + 2 * strlen (CC
)
351 + strlen (INC
) + strlen (macrofile
));
355 puts ("No more memory.");
360 sprintf (command
, fmt
, file_name
, CC
, INC
, CC
, macrofile
);
362 if (system (command
))
364 puts ("system() returned nonzero");
368 input
= fopen (macrofile
, "r");
372 printf ("Could not read %s: ", macrofile
);
377 while (fgets (line
, sizeof line
, input
) != NULL
)
382 if (strlen (line
) < 9 || line
[7] != ' ')
384 printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
389 for (i
= 0; i
< NUMBER_OF_PREFIXES
; ++i
)
391 if (!strncmp (line
+8, prefix
[i
], strlen (prefix
[i
]))) {
398 for (i
= 0; i
< NUMBER_OF_MACROS
; ++i
)
400 if (!strncmp (line
+ 8, macros
[i
], strlen (macros
[i
])))
408 /* Find next char after the macro identifier; this can be either
409 a space or an open parenthesis. */
410 endmac
= strcspn (line
+ 8, " (");
411 if (line
[8+endmac
] == '\0')
413 printf ("malformed input, expected '#define MACRO VALUE'\n"
418 for (i
= 0; i
< NUMBER_OF_SUFFIXES
; ++i
)
420 size_t len
= strlen (suffix
[i
]);
421 if (!strncmp (line
+ 8 + endmac
- len
, suffix
[i
], len
))
430 for (cpp
= except
; *cpp
!= NULL
; ++cpp
)
432 size_t len
= strlen (*cpp
);
433 if (!strncmp (line
+ 8, *cpp
, len
) && isspace (line
[8 + len
]))
441 fputs (line
, stdout
);