(root)/
glibc-2.38/
stdlib/
isomac.c
       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.
       4  
       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.
       9  
      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.
      14  
      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/>.  */
      18  
      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.
      26  
      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
      30     conforming
      31  
      32     #include <assert.h>
      33     #include <stdio.h>      <- or where the bogus macro is defined
      34     #include <string.h>
      35     #define STR(x) #x
      36     #define XSTR(x) STR(x)
      37     int main (void)
      38     {
      39       int PIPE_BUF = 0;
      40       assert (strcmp ("PIPE_BUF", XSTR (PIPE_BUF)) == 0);
      41       return 0;
      42     }
      43  
      44     is expected to compile and meet the assertion. If it does not, your
      45     compiler compiles some other language than Standard C.
      46  
      47     REQUIREMENTS:
      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.
      53  
      54     OUTPUT:
      55       Each header file name is printed, followed by illegal macro names
      56       and their definition. For the above example, you would see
      57       ...
      58       /usr/include/stdio.h
      59       #define PIPE_BUF 5120
      60       ...
      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
      63       found.  */
      64  
      65  #ifndef _GNU_SOURCE
      66  # define _GNU_SOURCE 1
      67  #endif
      68  
      69  #include <ctype.h>
      70  #include <stdio.h>
      71  #include <stdlib.h>
      72  #include <string.h>
      73  #include <unistd.h>
      74  
      75  #define HEADER_MAX          256
      76  
      77  static char macrofile[] = "/tmp/isomac.XXXXXX";
      78  
      79  /* ISO C header names including Amendment 1 (without ".h" suffix).  */
      80  static char *header[] =
      81  {
      82    "assert", "ctype", "errno", "float", "iso646", "limits", "locale",
      83    "math", "setjmp", "signal", "stdarg", "stddef", "stdio", "stdlib",
      84    "string", "time", "wchar", "wctype"
      85  };
      86  
      87  /* Macros with these prefixes are considered okay.  */
      88  static char *prefix[] =
      89  {
      90    "_", "E", "is", "str", "mem", "SIG", "FLT_", "DBL_", "LDBL_",
      91    "LC_", "wmem", "wcs"
      92  };
      93  
      94  /* Macros with these suffixes are considered okay.  Will not work for
      95     parametrized macros with arguments.  */
      96  static char *suffix[] =
      97  {
      98    "_MAX", "_MIN"
      99  };
     100  
     101  /* These macros are considered okay. In fact, these are just more prefixes.  */
     102  static char *macros[] =
     103  {
     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"
     166  };
     167  
     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)
     172  
     173  
     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";
     180  
     181  
     182  /* The compiler we use (given on the command line).  */
     183  char *CC;
     184  /* The -I parameters for CC to find all headers.  */
     185  char *INC;
     186  
     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 **);
     190  
     191  int
     192  main (int argc, char *argv[])
     193  {
     194    int h;
     195    int result = 0;
     196    const char **ignore_list;
     197  
     198    CC = argc > 1 ? argv[1] : "gcc";
     199    INC = argc > 2 ? argv[2] : "";
     200  
     201    if (system (NULL) == 0)
     202      {
     203        puts ("Sorry, no command processor.");
     204        return EXIT_FAILURE;
     205      }
     206  
     207    /* First get list of symbols which are defined by the compiler.  */
     208    ignore_list = get_null_defines ();
     209  
     210    fputs ("Tested files:\n", stdout);
     211  
     212    for (h = 0; h < NUMBER_OF_HEADERS; ++h)
     213      {
     214        char file_name[HEADER_MAX];
     215        sprintf (file_name, "%s.h", header[h]);
     216        result |= check_header (file_name, ignore_list);
     217      }
     218  
     219    remove (macrofile);
     220  
     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.  */
     223    return result;
     224  }
     225  
     226  
     227  static char *
     228  xstrndup (const char *s, size_t n)
     229  {
     230    size_t len = n;
     231    char *new = malloc (len + 1);
     232  
     233    if (new == NULL)
     234      return NULL;
     235  
     236    new[len] = '\0';
     237    return memcpy (new, s, len);
     238  }
     239  
     240  
     241  static const char **
     242  get_null_defines (void)
     243  {
     244    char line[BUFSIZ], *command;
     245    char **result = NULL;
     246    size_t result_len = 0;
     247    size_t result_max = 0;
     248    FILE *input;
     249    int first = 1;
     250  
     251    int fd = mkstemp (macrofile);
     252    if (fd == -1)
     253      {
     254        printf ("mkstemp failed: %m\n");
     255        exit (1);
     256      }
     257    close (fd);
     258  
     259    command = malloc (sizeof fmt + sizeof "/dev/null" + 2 * strlen (CC)
     260  		    + strlen (INC) + strlen (macrofile));
     261  
     262    if (command == NULL)
     263      {
     264        puts ("No more memory.");
     265        exit (1);
     266      }
     267  
     268    sprintf (command, fmt, "/dev/null", CC, INC, CC, macrofile);
     269  
     270    if (system (command))
     271      {
     272        puts ("system() returned nonzero");
     273        free (command);
     274        return NULL;
     275      }
     276    free (command);
     277    input = fopen (macrofile, "r");
     278  
     279    if (input == NULL)
     280      {
     281        printf ("Could not read %s: ", macrofile);
     282        perror (NULL);
     283        return NULL;
     284      }
     285  
     286    while (fgets (line, sizeof line, input) != NULL)
     287      {
     288        int i, okay = 0;
     289        size_t endmac;
     290        char *start, *end;
     291        if (strlen (line) < 9 || line[7] != ' ')
     292  	{ /* "#define A" */
     293  	  printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
     294  		  line);
     295  	  continue;
     296  	}
     297        if (line[8] == '_')
     298  	/* It's a safe identifier.  */
     299  	continue;
     300        if (result_len == result_max)
     301  	{
     302  	  result_max += 10;
     303  	  result = realloc (result, result_max * sizeof (char **));
     304  	  if (result == NULL)
     305  	    {
     306  	      puts ("No more memory.");
     307  	      exit (1);
     308  	    }
     309  	}
     310        start = &line[8];
     311        for (end = start + 1; !isspace (*end) && *end != '\0'; ++end)
     312  	;
     313        result[result_len] = xstrndup (start, end - start);
     314  
     315        if (strcmp (result[result_len], "IN_MODULE") != 0)
     316  	{
     317  	  if (first)
     318  	    {
     319  	      fputs ("The following identifiers will be ignored since the compiler defines them\nby default:\n", stdout);
     320  	      first = 0;
     321  	    }
     322  	  puts (result[result_len]);
     323  	}
     324        ++result_len;
     325      }
     326    if (result_len == result_max)
     327      {
     328        result_max += 1;
     329        result = realloc (result, result_max * sizeof (char **));
     330        if (result == NULL)
     331  	{
     332  	  puts ("No more memory.");
     333  	  exit (1);
     334  	}
     335      }
     336    result[result_len] = NULL;
     337    fclose (input);
     338  
     339    return (const char **) result;
     340  }
     341  
     342  
     343  static int
     344  check_header (const char *file_name, const char **except)
     345  {
     346    char line[BUFSIZ], *command;
     347    FILE *input;
     348    int result = 0;
     349  
     350    command = malloc (sizeof fmt + strlen (file_name) + 2 * strlen (CC)
     351  		    + strlen (INC) + strlen (macrofile));
     352  
     353    if (command == NULL)
     354      {
     355        puts ("No more memory.");
     356        exit (1);
     357      }
     358  
     359    puts (file_name);
     360    sprintf (command, fmt, file_name, CC, INC, CC, macrofile);
     361  
     362    if (system (command))
     363      {
     364        puts ("system() returned nonzero");
     365        result = 1;
     366      }
     367    free (command);
     368    input = fopen (macrofile, "r");
     369  
     370    if (input == NULL)
     371      {
     372        printf ("Could not read %s: ", macrofile);
     373        perror (NULL);
     374        return 1;
     375      }
     376  
     377    while (fgets (line, sizeof line, input) != NULL)
     378      {
     379        int i, okay = 0;
     380        size_t endmac;
     381        const char **cpp;
     382        if (strlen (line) < 9 || line[7] != ' ')
     383  	{ /* "#define A" */
     384  	  printf ("Malformed input, expected '#define MACRO'\ngot '%s'\n",
     385  		  line);
     386  	  result = 1;
     387  	  continue;
     388  	}
     389        for (i = 0; i < NUMBER_OF_PREFIXES; ++i)
     390  	{
     391  	  if (!strncmp (line+8, prefix[i], strlen (prefix[i]))) {
     392  	    ++okay;
     393  	    break;
     394  	  }
     395  	}
     396        if (okay)
     397  	continue;
     398        for (i = 0; i < NUMBER_OF_MACROS; ++i)
     399  	{
     400  	  if (!strncmp (line + 8, macros[i], strlen (macros[i])))
     401  	    {
     402  	      ++okay;
     403  	      break;
     404  	    }
     405  	}
     406        if (okay)
     407  	continue;
     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')
     412  	{
     413  	  printf ("malformed input, expected '#define MACRO VALUE'\n"
     414  		  "got '%s'\n", line);
     415  	  result = 1;
     416  	  continue;
     417  	}
     418        for (i = 0; i < NUMBER_OF_SUFFIXES; ++i)
     419  	{
     420  	  size_t len = strlen (suffix[i]);
     421  	  if (!strncmp (line + 8 + endmac - len, suffix[i], len))
     422  	    {
     423  	      ++okay;
     424  	      break;
     425  	    }
     426  	}
     427        if (okay)
     428  	continue;
     429        if (except != NULL)
     430  	for (cpp = except; *cpp != NULL; ++cpp)
     431  	  {
     432  	    size_t len = strlen (*cpp);
     433  	    if (!strncmp (line + 8, *cpp, len) && isspace (line[8 + len]))
     434  	      {
     435  		++okay;
     436  		break;
     437  	      }
     438  	  }
     439        if (!okay)
     440  	{
     441  	  fputs (line, stdout);
     442  	  result = 2;
     443  	}
     444      }
     445    fclose (input);
     446  
     447    return result;
     448  }
     449  
     450  /* EOF */