List:Commits« Previous MessageNext Message »
From:Marc Alff Date:August 24 2010 9:25pm
Subject:Re: bzr commit into mysql-trunk-bugfixing branch (marc.alff:3197)
View as plain text  
Hi Guilhelm

On 8/23/10 6:34 AM, Guilhem Bichot wrote:
> Hello Marc,
> Marc Alff a écrit, Le 11.08.2010 19:00:
>> #At file:///Users/malff/BZR_TREE/mysql-trunk-bugfixing-55873/ based on
>> revid:jonathan.perkin@stripped
>> 3197 Marc Alff 2010-08-11
>> Bug#55873 short startup options do not work in 5.5
>> Before this fix, the server did not recognize 'short' (as in -a) options
>> but only 'long' (as in --ansi) options in the startup command line.
>> The root cause is that handle_options() did not honor the
>> my_getopt_skip_unknown flag
>> when parsing 'short' options.
>> The fix changes handle_options(), so that my_getopt_skip_unknown is
>> honored in all cases.
>> === added file 'mysql-test/suite/perfschema/t/bad_option_4.test'
>> +
>> +let $outfile= $MYSQLTEST_VARDIR/tmp/bad_option_4.txt;
>> +--error 0,1
>> +--remove_file $outfile
>> +--error 1
>> +--exec $MYSQLD_BOOTSTRAP_CMD --loose-console -a -h bad_option_h_param
>> > $outfile 2>&1
> Here the test expects that mysqld will fail because there is no
> directory named bad_option_h_param. A failure proves that
> bad_option_h_param properly passes the first call to handle_options()
> (which is restricted to perfschema options), thanks to
> my_getopt_skip_unknown, and then lands into the second call to
> handle_options where -h is handled and the argument is detected as a
> non-existent directory. All fine.
> To make the test more precise, how about making it grep for
> Can't change dir to.*bad_option_h_param
> instead of just
> bad_option_h_param ,
> if technically possible?

Yes, it works as is. I will use this in later patches.

> The latter pattern is less selective, it could match even if the server
> was buggy and rejected bad_option_h_param in the first handle_options()
> call with something like "unknown option bad_option_h_param".

I agree.

> Your many tests are very good.
>> === modified file 'mysys/my_getopt.c'
>> --- a/mysys/my_getopt.c 2010-07-16 21:00:50 +0000
>> +++ b/mysys/my_getopt.c 2010-08-11 17:00:26 +0000
>> @@ -464,6 +464,17 @@ int handle_options(int *argc, char ***ar
>> }
>> if (!opt_found)
>> {
>> + if (my_getopt_skip_unknown)
>> + {
>> + /*
>> + Preserve this unknown short option.
>> + If there are any parameters associated with this short option,
>> + as in "-X p1 p2 p3", parameters like p1 p2 p3 will be copied
>> + in the result by the outer loop.
>> + */
>> + (*argv)[argvpos++]= *pos;
>> + break;
>> + }
> The corresponding code for long options has a do...while() instead.
> After reading handle_options() I cannot see a case where the do...while
> will do more than one iteration (i.e. where pos!=first). I'm not asking
> you to change do...while to be a single iteration (like your new code
> above), it's a detail and I don't want to introduce a subtle bug, just
> would like to know whether you agree on the observation or I'm missing
> something.

This is also my understanding of the code.
The loop is useless, but does not seem to cause any harm,
so I avoided touching it to avoid introducing more risk.

> There is a problem with the new "break;" above: it will break out of
> for (optend= cur_arg etc)
> and come to
> if ((error= setval(optp, value, argument, set_maximum_value)))
> below, which will do a setval() for a non-identified option.

Yes, you are correct.
Overall, handle_option() just feels like spaghetti code, and the fix was 

While analysing this code again after a week of rest, I think there is 
much more to it, and that the issue is not that easy to resolve.

In particular, consider the following loop:

       else  /* must be short option */
         for (optend= cur_arg; *optend; optend++)

My current understanding of this loop is that the code attempts to find 
*several* short options in the *same* argv[i] command line argument.

For example, "mysqld -alw5" is interpreted as "mysqld -a -l -w5"

The problem here is that I don't see how the server can parse "-XYZ" 
without knowing if X, Y and Z are options of not, that takes argument or 
not, because "-XYZ" could mean:
-X -Y -Z, where X Y and Z are short options with no arguments
-X -YZ, where Y is a short option with a value of Z
-XYZ, where X is a short option with a value of YZ

My conclusion then is that handle_option() can _NOT_ honor the skip 
unknown options flag and support this syntax at the same time, for short 
options all concatenated in the same argv[] argument.

Please confirm whether this is also your analysis, or if you find 
something missing.

At this point, I think the solutions to resolve the bug are:

1) Get rid of short options all together in 5.5
This is what the bug reporter actually suggested.

2) Continue to support short options in 5.5, but only with the explicit 
"-X -Y -Z" syntax, and not with the "-XYZ" syntax.
In that case, supporting my_getopt_skip_unknown in handle_options() for 
short options seems possible and not too intrusive.

This will be an incompatible change, forcing users to replace
"-anCutf8" with "-a -n -Cutf8",
or better with "--ansi --new --character_set_server=utf8".

I actually see this as a good thing.

Another option I explored was:

3) declare every options that has a "short" name as PARSE_EARLY, and 
reorder the initialization code accordingly, so that every short option 
is known to handle_options() the first time, so the code does not need 
to support my_getopt_skip_unknown.
This is however creating chaos in main_mysqld, and is a fix that I 
consider way to risky and way to intrusive.
The problem here is that:
- reordering options (between PARSE_EARLY and PARSE_NORMAL) based on the 
option *semantic* is ok: very low levels (performance schema, logging, 
...) are ok to parse first.
- reordering options based on whether there is a short hand notation or 
not, regardless of the option semantic and what it controls, just 
completely destabilize this otherwise very fragile initialization 
sequence. The embedded server initialization is deeply impacted too.

In short, I don't think 3) is viable.

Before going further, please let me know if you see another solution to 
this. My preference so far is 2).

-- Marc

bzr commit into mysql-trunk-bugfixing branch (marc.alff:3197) Bug#55873Marc Alff11 Aug
  • Re: bzr commit into mysql-trunk-bugfixing branch (marc.alff:3197)Bug#55873Guilhem Bichot23 Aug
    • Re: bzr commit into mysql-trunk-bugfixing branch (marc.alff:3197)Bug#55873Marc Alff24 Aug
      • Re: bzr commit into mysql-trunk-bugfixing branch (marc.alff:3197)Bug#55873Guilhem Bichot25 Aug