[Top][All Lists]

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

Re: [Qemu-block] [PATCH v2] qemu-io: Reinitialize optind to 1 (not 0) be

From: Eric Blake
Subject: Re: [Qemu-block] [PATCH v2] qemu-io: Reinitialize optind to 1 (not 0) before parsing inner command.
Date: Mon, 7 Jan 2019 12:45:29 -0600
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.1

On 1/7/19 12:14 PM, Max Reitz wrote:
> On 07.01.19 18:59, Eric Blake wrote:
>> On 1/7/19 11:50 AM, Max Reitz wrote:
>>>>>> Note I didn't set optreset.  It's not present in glibc and the "hard
>>>>>> reset" is not necessary in this context.
>>>>> But it sure sounds like FreeBSD requires you to set it, doesn't it?
>> No.  Quoting https://www.freebsd.org/cgi/man.cgi?getopt(3)
>>      The variables opterr and optind are both initialized to 1.       The 
>> optind
>>      variable may be set to another value before a set of calls      to
>> getopt() in
>>      order to skip over      more or less argv entries.
>> so resetting it to 1 as a soft reset is no different to setting it to 2
>> to skip argv[1].
> In theory it is very much different because the text clearly says "in
> order to skip", not "in order to re-parse or use a different argv".
> Especially the fact that we use different argvs is something that
> implementations may not expect.

Consider the following input:

./prog -ab -cd -ef


while ((opt = getopt(argc, argv, "abcdef")) != -1) {
  switch (opt) {
   case 'a': case 'b': case 'f': break;
   case 'c': optind = 3; break;
   case 'd': case 'e': abort();

What does that do on BSD?  On glibc, after the third call, optind is
still 2 (but I hard-set it to 3), then the fourth call returns 'd' and
increments optind to 4, before abort()ing, never reaching 'e' or 'f'.
But if BSD goes from 'c' to 'f' and skips 'd' and 'e', it is because BSD
tracks internal state differently from glibc.  Either way, the fact that
setting optind = 3 does NOT make glibc return 'e' or 'f' means that I
did NOT skip ahead to argument 3 (glibc still returned 'd' then skipped
to argument 4; either BSD does the same, or BSD skips to 'f'), and thus
I can argue that the BSD man page is incomplete, and SHOULD be corrected
to mention that assigning to optind to skip to a future argument is safe
ONLY when the hidden state is not affected by being mid-parse of merged
short options.  But how do you get out of the hidden state of merged
short options? By parsing until getopt() returns -1.  And once you've
reached that point, then hidden state is clear, and skipping backwards
is just as reasonable as skipping forwards.

>> I think the BSD man page needs updating, and that will probably happen
>> if I file my promised POSIX defect.
> Sure.  But as it is, it doesn't tell me that resetting optind to 1 is
> sufficient to be able to parse a new argv.

But arguing that something that worked for Richard's testing is wrong,
without reading the BSD source code, isn't going to help us either.

>> I don't see the point - Richard has already tested that optind = 1
>> worked on BSD machines for our purposes, so we don't have to worry about
>> the hard reset aspect of optreset=1.
> Well, and as far as I remember glibc's memcpy() at one point only copied
> in one direction and things broke badly once they reversed it at some
> point for some CPUs.

That was because of buggy software that didn't read the function
contracts, and should have been using memmove( insta

> Just because it works now doesn't mean it will work always if the
> specification allows for different behavior.

Yes, but that's why I need to file a POSIX defect, so that BSD won't
change their current behavior because POSIX will require the soft reset

Here's the current thread on the POSIX list:

which I hope to turn into a formal defect soon.

>> (But yes, it would also be nice if
>> BSD and glibc folks could agree on how to do hard resets, instead of
>> having two different incompatible ways)
> I don't see why we should have a general code path if there is no
> standard way of resetting getopt() other than "This seems to work".
> What's so bad about a weak optreset or an
> "#ifdef __FreeBSD__; optreset = 1; #endif"?
> Sure, if you can get POSIX to define the fact that optind = 1 after
> getopt() == -1 will be sufficient to start parsing a new argv, that'd be
> great.  But there is no such standard yet (other than "Why would that
> not work?").

Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature

reply via email to

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