Bug#192834: Glibc's method of resetting getopt different, causes interoperability problems
On Fri, Oct 08, 2004 at 10:55:44AM +0900, GOTO Masanori wrote:
> > It would be nice if glibc reset its internal state if when optind is set
> > to 1, as well as when optind is set to 0. Historically, the mechanism
> > which worked across BSD, AT&T, and most commercial unix systems derived
> > from the same require that getopt() be reset by setting optind to 1.
> > Setting optind to 0 causes getopt() to misbehave on a number of
> > platforms, most notably and most recently Mac OS X, but probably on
> > other BSD-derived systems.
> > On the other hand, setting optind to 1 in an attempt to reset things
> > causes glibc to core dump under some conditions.
> > The lack of interoperability on this point means that I was forced to
> > work around the bug in a particularly ugly fashion, as shown below.
> > It would be really nice if I didn't need this kind of kludgery.
> Glibc defines optind = 1 in initial state in 2.3.2.ds1-17. POSIX says
> it should be 1 before any calls. Could you provide us more
> information or an example to reappear this report?
The problem is what happens if you want to use getopt() multiple times
to parse multiple sets of argc/argv arguments. For example,
e2fsprogs's debugfs program uses getopt to parse each command given to
# debugfs /dev/hda3
debugfs: stat /
debugfs: clri <2>
In this case, "stat /", "clri <2>", and "quit" are all parsed using
getopt(), as well as being the command-line arguments to debugfs.
Unfortunately, gnu glibc has extra allocated memory which is used to
support long options (i.e., --help). This information is only reset
when you set optind=0 before calling getopt() to parse a new set of
argv vectors. If you do not reset optind to 0 before parsing a new
set of argv vectors, getopt will core dump. Unfortunately, on BSD
systems, you have to set optind=1 before parsing a new set of argv
vectors, or BSD systems will core dump.
To reproduce, recompile e2fsprogs and remove the magic GLIBC branch
below, and if you always reinitialize optind=1 in reset_getopt(), you
will watch getopt core dump rather spectacularly after executing a
number of debugfs commands with and without options.
* This function resets the libc getopt() function, which keeps
* internal state. Bad design! Stupid libc API designers! No
* BSD-derived getopt() functions require that optind be reset to 1 in
* order to reset getopt() state. This used to be generally accepted
* way of resetting getopt(). However, glibc's getopt()
* has additional getopt() state beyond optind, and requires that
* optind be set zero to reset its state. So the unfortunate state of
* affairs is that BSD-derived versions of getopt() misbehave if
* Optind is set to 0 in order to reset getopt(), and glibc's getopt()
* will core ump if optind is set 1 in order to reset getopt().
* More modern versions of BSD require that optreset be set to 1 in
* order to reset getopt(). Sigh. Standards, anyone?
* We hide the hair here.
optind = 0;
optind = 1;
optreset = 1; /* Makes BSD getopt happy */