This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/2679] New: getopt and optind (when called with different arguments)


I found a strange behavior in getopt that raises when getopt (or
getopt_long) is called with new argv and argc w.r.t. the ones used in
a previous invocation (in the same process).

Actually this might seem a strange situation, since you usually pass
the argc and argv passed to the main function.  However, I'm using
getopt_long to parse options that are not always the one passed at
command line: they might come from a configuration file, or might be
stored somewhere else.  

I'm the maintainer of GNU gengetopt that generates command line
parsers, and in general option parsers, that use getopt_long.  Thus a
program, can parse the command line, then a configuration file, and so
getopt_long is called with different arguments (string vectors).
optind is set to 1, each time new arguments are used (as requested by
the documentation).

However, sometimes, in such context, some strange behaviors are
experienced and most of the time also illegal accesses to memory
(reported by valgrind, or segfaults).

Taking a look at the getopt.c I see the following code (part of
_getopt_internal_r function):

  if (d->optind == 0 || !d->__initialized)
    {
      if (d->optind == 0)
	d->optind = 1;	/* Don't scan ARGV[0], the program name.  */
      optstring = _getopt_initialize (argc, argv, optstring, d);
      d->__initialized = 1;
    }

where d is the _getopt_data struct containing also pointers such as
__next_char and argv indexes such as __first_nonopt and __last_nonopt.

Now, these elements are initiliazed only the first time or when optind
== 0.  

That's basically the problem: when getopt_long is called with new
argv, since optind is set to 1, the internal structure is not
initialized again, and then it contains pointers to the previous
vector, resulting in strange behaviors or also illegal memory accesses
if the previous vector has already been deallocated, or if the
previous vector had bigger size than the current one.

I seem to understand that the solution is that optind should be set to
0 before any new use of getopt_long, but this is not documented
anywhere but in the source:

"On entry to `getopt', zero means this is the first call; initialize."

and this does not seem to be standard, since optind should be 1
before any call, as also noted in the getopt.c itself:

/* 1003.2 says this must be 1 before any call.  */

I think that the above check should actually be

  if (d->optind == 0 || d->optind == 1 || !d->__initialized)
    {
      if (d->optind == 0)
	d->optind = 1;	/* Don't scan ARGV[0], the program name.  */
      optstring = _getopt_initialize (argc, argv, optstring, d);
      d->__initialized = 1;
    }

i.e., the initialization should be performed even when optind == 1
since "optind must be 1 before any call".

By users of gengetopt I was reported that by using other
implementation of getopt_long, setting optind = 0 makes also the
program name to be interpreted as an option (since it is in position 0
in argv), which, although odd, it is more obvious since optind "is the
index of the next element of the ARGV array to be processed".

Thus setting optind to 0 before the initial invocations makes GNU
gengetopt generate code that would work only with GNU implementation
of getopt, due to feature that I seem to understand as not standard,
and not documented (and thus are allowed to change in the future,
breaking existing code relying on it)...

or am I missing something?

Otherwise I guess the above proposed modification is correct.

-- 
           Summary: getopt and optind (when called with different arguments)
           Product: glibc
           Version: 2.4
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
        AssignedTo: drepper at redhat dot com
        ReportedBy: bettini at dsi dot unifi dot it
                CC: glibc-bugs at sources dot redhat dot com


http://sourceware.org/bugzilla/show_bug.cgi?id=2679

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]