bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-gnulib] getopt fix to prevent it from lying to the compiler about c


From: Paul Eggert
Subject: [Bug-gnulib] getopt fix to prevent it from lying to the compiler about const
Date: Thu, 11 Nov 2004 14:58:51 -0800
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

While we're on the subject of getopt, it's long bothered me that GNU
getopt lies to the compiler about whether its argv parameter is a
pointer to a const.  This leads to undefined behavior, according to
C99.  It may be too late to fix this problem in glibc, since the
existing API has been broken for years and people are used to it that
way, but it's not too late to fix it in gnulib -- and perhaps if we do
it the "right" way in gnulib for a while, we might be able to convince
glibc to fix it too.

So I installed this patch.

This patch also fixes a typo in my previous patch: I forgot to
include <stdlib.h> and <stdio.h>.

2004-11-11  Paul Eggert  <address@hidden>

        * lib/getopt_.h (__getopt_argv_const): New macro, to be used so that
        we can stop lying to compilers about the constness of argv when we
        are compiled outside glibc.
        (getopt, getopt_long, getopt_long_only): Use it.
        * lib/getopt.c (_getopt_initialize, _getopt_internal_r,
        _getopt_internal, getopt): Likewise.
        * lib/getopt1.c (getopt_long, _getopt_long_r, getopt_long_only,
        _getopt_long_only_r): Likewise.
        * lib/getopt_int.h (_getopt_internal, _getopt_internal_r,
        _getopt_long_r, _getopt_long_only_r): Likewise.

        * lib/getopt_.h [defined __GETOPT_PREFIX && !defined __need_getopt]:
        Include <stdlib.h> and <stdio.h>.

Index: lib/getopt_.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getopt_.h,v
retrieving revision 1.2
diff -p -u -r1.2 getopt_.h
--- lib/getopt_.h       11 Nov 2004 20:24:58 -0000      1.2
+++ lib/getopt_.h       11 Nov 2004 21:11:25 -0000
@@ -25,13 +25,15 @@
 
 /* Standalone applications should #define __GETOPT_PREFIX to an
    identifier that prefixes the external functions and variables
-   defined in this header.  When this happens, include <unistd.h> (the
-   standard header declaring getopt), so that it will not cause
-   confusion if it is included later.  Then systematically rename
+   defined in this header.  When this happens, include the
+   headers that might declare getopt so that they will not cause
+   confusion if included after this file.  Then systematically rename
    identifiers so that they do not collide with the system functions
    and variables.  Renaming avoids problems with some compilers and
    linkers.  */
 #if defined __GETOPT_PREFIX && !defined __need_getopt
+# include <stdlib.h>
+# include <stdio.h>
 # if HAVE_UNISTD_H
 #  include <unistd.h>
 # endif
@@ -51,6 +53,18 @@
 # define optopt __GETOPT_PREFIX##optopt
 #endif
 
+/* The elements of the ARGV arguments to getopt aren't really const,
+   because we permute them.  For glibc, __getopt_argv_const is const
+   so that prototypes pretend the elements are const, to be compatible
+   with Posix.  However, drop this pretense for standalone
+   applications, since it's not needed there and it's safer not to lie
+   to compilers.  */
+#ifdef __GETOPT_PREFIX
+# define __getopt_argv_const /* empty */
+#else
+# define __getopt_argv_const const
+#endif
+
 /* If __GNU_LIBRARY__ is not already defined, either we are being used
    standalone, or this is the first header included in the source file.
    If we are being used with glibc, we need to include <features.h>, but
@@ -172,15 +186,16 @@ struct option
    arguments to the option '\0'.  This behavior is specific to the GNU
    `getopt'.  */
 
-extern int getopt (int ___argc, char *const *___argv, const char *__shortopts)
+extern int getopt (int ___argc, char *__getopt_argv_const *___argv,
+                  const char *__shortopts)
        __THROW;
 
 #ifndef __need_getopt
-extern int getopt_long (int ___argc, char *const *___argv,
+extern int getopt_long (int ___argc, char *__getopt_argv_const *___argv,
                        const char *__shortopts,
                        const struct option *__longopts, int *__longind)
        __THROW;
-extern int getopt_long_only (int ___argc, char *const *___argv,
+extern int getopt_long_only (int ___argc, char *__getopt_argv_const *___argv,
                             const char *__shortopts,
                             const struct option *__longopts, int *__longind)
        __THROW;
Index: lib/getopt.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getopt.c,v
retrieving revision 1.43
diff -p -u -r1.43 getopt.c
--- lib/getopt.c        12 Aug 2004 07:59:56 -0000      1.43
+++ lib/getopt.c        11 Nov 2004 21:11:25 -0000
@@ -250,8 +250,8 @@ exchange (char **argv, struct _getopt_da
 /* Initialize the internal data when the first call is made.  */
 
 static const char *
-_getopt_initialize (int argc, char *const *argv, const char *optstring,
-                   struct _getopt_data *d)
+_getopt_initialize (int argc, char *__getopt_argv_const *argv,
+                   const char *optstring, struct _getopt_data *d)
 {
   /* Start processing options with ARGV-element 1 (since ARGV-element 0
      is the program name); the sequence of previously skipped
@@ -356,8 +356,9 @@ _getopt_initialize (int argc, char *cons
    if the `flag' field is zero.
 
    The elements of ARGV aren't really const, because we permute them.
-   But we pretend they're const in the prototype to be compatible
-   with other systems.
+   If __getopt_argv_const is defined to const, pretend they're
+   const in the prototype to be compatible with Posix.
+   But tell the truth if __getopt_argv_const is defined to empty.
 
    LONGOPTS is a vector of `struct option' terminated by an
    element containing a name which is zero.
@@ -370,7 +371,8 @@ _getopt_initialize (int argc, char *cons
    long-named options.  */
 
 int
-_getopt_internal_r (int argc, char *const *argv, const char *optstring,
+_getopt_internal_r (int argc, char *__getopt_argv_const *argv,
+                   const char *optstring,
                    const struct option *longopts, int *longind,
                    int long_only, struct _getopt_data *d)
 {
@@ -1135,7 +1137,8 @@ _getopt_internal_r (int argc, char *cons
 }
 
 int
-_getopt_internal (int argc, char *const *argv, const char *optstring,
+_getopt_internal (int argc, char *__getopt_argv_const *argv,
+                 const char *optstring,
                  const struct option *longopts, int *longind, int long_only)
 {
   int result;
@@ -1154,7 +1157,7 @@ _getopt_internal (int argc, char *const 
 }
 
 int
-getopt (int argc, char *const *argv, const char *optstring)
+getopt (int argc, char *__getopt_argv_const *argv, const char *optstring)
 {
   return _getopt_internal (argc, argv, optstring,
                           (const struct option *) 0,
Index: lib/getopt1.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getopt1.c,v
retrieving revision 1.17
diff -p -u -r1.17 getopt1.c
--- lib/getopt1.c       12 Aug 2004 08:00:14 -0000      1.17
+++ lib/getopt1.c       11 Nov 2004 21:11:25 -0000
@@ -41,14 +41,14 @@
 #endif
 
 int
-getopt_long (int argc, char *const *argv, const char *options,
+getopt_long (int argc, char *__getopt_argv_const *argv, const char *options,
             const struct option *long_options, int *opt_index)
 {
   return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
 }
 
 int
-_getopt_long_r (int argc, char *const *argv, const char *options,
+_getopt_long_r (int argc, char *__getopt_argv_const *argv, const char *options,
                const struct option *long_options, int *opt_index,
                struct _getopt_data *d)
 {
@@ -62,14 +62,16 @@ _getopt_long_r (int argc, char *const *a
    instead.  */
 
 int
-getopt_long_only (int argc, char *const *argv, const char *options,
+getopt_long_only (int argc, char *__getopt_argv_const *argv,
+                 const char *options,
                  const struct option *long_options, int *opt_index)
 {
   return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
 }
 
 int
-_getopt_long_only_r (int argc, char *const *argv, const char *options,
+_getopt_long_only_r (int argc, char *__getopt_argv_const *argv,
+                    const char *options,
                     const struct option *long_options, int *opt_index,
                     struct _getopt_data *d)
 {
Index: lib/getopt_int.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getopt_int.h,v
retrieving revision 1.1
diff -p -u -r1.1 getopt_int.h
--- lib/getopt_int.h    9 Mar 2004 19:42:23 -0000       1.1
+++ lib/getopt_int.h    11 Nov 2004 21:11:25 -0000
@@ -20,7 +20,7 @@
 #ifndef _GETOPT_INT_H
 #define _GETOPT_INT_H  1
 
-extern int _getopt_internal (int ___argc, char *const *___argv,
+extern int _getopt_internal (int ___argc, char *__getopt_argv_const *___argv,
                             const char *__shortopts,
                             const struct option *__longopts, int *__longind,
                             int __long_only);
@@ -110,17 +110,18 @@ struct _getopt_data
    default values and to clear the initialization flag.  */
 #define _GETOPT_DATA_INITIALIZER       { 1, 1 }
 
-extern int _getopt_internal_r (int ___argc, char *const *___argv,
+extern int _getopt_internal_r (int ___argc, char *__getopt_argv_const *___argv,
                               const char *__shortopts,
                               const struct option *__longopts, int *__longind,
                               int __long_only, struct _getopt_data *__data);
 
-extern int _getopt_long_r (int ___argc, char *const *___argv,
+extern int _getopt_long_r (int ___argc, char *__getopt_argv_const *___argv,
                           const char *__shortopts,
                           const struct option *__longopts, int *__longind,
                           struct _getopt_data *__data);
 
-extern int _getopt_long_only_r (int ___argc, char *const *___argv,
+extern int _getopt_long_only_r (int ___argc,
+                               char *__getopt_argv_const *___argv,
                                const char *__shortopts,
                                const struct option *__longopts,
                                int *__longind,




reply via email to

[Prev in Thread] Current Thread [Next in Thread]