sort +POS -POS

Version:

coreutils-8.4 (fixed in 8.5)

How to reproduce?

1. create a file sort.txt with the content below:

perra/S perra 2.200000

perra/S perra 4.400000

2. $ coreutils-8.4/src/sort +1 -2 +2r -3 -f sort.txt

perra/S perra 2.200000

perra/S perra 4.400000

Symptom:

Wrong result. The correct result should be:

$ coreutils-8.5/src/sort +1 -2 +2r -3 -f sort.txt

perra/S perra 4.400000

perra/S perra 2.200000

Background:

http://lowfatlinux.com/linux-sort.html

sort +pos1 -pos2 is to sort start at the key at “pos1+1” and end at the last character of pos2,

so “+1 -2 +2r -3” means the first sort key start at 2 and end at 2, which is “perra” in our input. The 2nd sort key (if the first sort key equals) starts at 3 and end at 3 (2.20000 in our case). The ‘r’ means it should be sorted in the reverse order, with highest value first.

Root cause:

In the buggy version, when parsing the first sort key “+1 -2”, it mistakenly treated as “+1 -3”, so treat the sort key as “perra 4.400000” instead of “perra”. It uses a var “key->eword” to represent the end of sorting field. In the buggy version, when processing “+1 -2”, the “key->eword” equals to 2. Since it’s zero origin, so this means the sort field ends at the 3rd field, which is “4.400000”. The fix is to minus it by 1 before further sorting.

int  main (int argc, char **argv)

{

 .. .. ..

 if (minus_pos_usage)

 {

   char const *optarg1 = argv[optind++];

   s = parse_field_count (optarg1 + 1, &key->eword,

                 N_("invalid number after `-'"));

  /* After the parsing above, it parsed “+2”, with key->eword set to 2.

     s points to the next input character, in this case a space. It tests

     *s against ‘.’ because sort allow the format “+2.0”. However, it did

     not test the false branch (else case), which will cause the execution

     to continue with a wrong ‘key->eword’. */

  if (*s == '.')            

     <---- they didn’t test else case. as long as s!=’.’ they will meet the buggy execution

       s = parse_field_count (s + 1, &key->echar,

                N_("invalid number after `.'"));

/* patch: further test if key->eword need to be decreased. */  

++        if (!key->echar && key->eword)

++         {                                  

++         key->eword--;

++        }

}

Is there any error message?

No.

Can Errlog insert an error message?

Yes. The else branch of ‘if (*s == “.”)’ above is not tested, and Errlog can insert a msg like:

  if (*s == '.')            

       … .. ..

+  else

+      elog(...);