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
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(...);