regexec: Fix off-by-one bug in weight comparison [BZ #23036]

Each weight is prefixed by its length, and the length does not include
itself in the count.  This can be seen clearly from the find_idx
function in string/strxfrm_l.c, for example.  The old code behaved as if
the length itself counted, thus comparing an additional byte after the
weight, leading to spurious comparison failures and incorrect further
partitioning of character equivalence classes.
This commit is contained in:
Florian Weimer 2018-07-10 11:18:26 +02:00
parent 4fa34da679
commit 7b2f4cedf0
2 changed files with 27 additions and 23 deletions

View File

@ -1,3 +1,10 @@
2018-07-10 Florian Weimer <fweimer@redhat.com>
[BZ #23036]
* posix/regexec.c (check_node_accept_bytes): When comparing
weights, do not compare an extra byte after the end of the
weights.
2018-07-10 Florian Weimer <fweimer@redhat.com> 2018-07-10 Florian Weimer <fweimer@redhat.com>
* libio/readline.c: Fix copyright year. * libio/readline.c: Fix copyright year.

View File

@ -3878,30 +3878,27 @@ check_node_accept_bytes (const re_dfa_t *dfa, Idx node_idx,
indirect = (const int32_t *) indirect = (const int32_t *)
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
int32_t idx = findidx (table, indirect, extra, &cp, elem_len); int32_t idx = findidx (table, indirect, extra, &cp, elem_len);
int32_t rule = idx >> 24;
idx &= 0xffffff;
if (idx > 0) if (idx > 0)
for (i = 0; i < cset->nequiv_classes; ++i) {
{ size_t weight_len = weights[idx];
int32_t equiv_class_idx = cset->equiv_classes[i]; for (i = 0; i < cset->nequiv_classes; ++i)
size_t weight_len = weights[idx & 0xffffff]; {
if (weight_len == weights[equiv_class_idx & 0xffffff] int32_t equiv_class_idx = cset->equiv_classes[i];
&& (idx >> 24) == (equiv_class_idx >> 24)) int32_t equiv_class_rule = equiv_class_idx >> 24;
{ equiv_class_idx &= 0xffffff;
Idx cnt = 0; if (weights[equiv_class_idx] == weight_len
&& equiv_class_rule == rule
idx &= 0xffffff; && memcmp (weights + idx + 1,
equiv_class_idx &= 0xffffff; weights + equiv_class_idx + 1,
weight_len) == 0)
while (cnt <= weight_len {
&& (weights[equiv_class_idx + 1 + cnt] match_len = elem_len;
== weights[idx + 1 + cnt])) goto check_node_accept_bytes_match;
++cnt; }
if (cnt > weight_len) }
{ }
match_len = elem_len;
goto check_node_accept_bytes_match;
}
}
}
} }
} }
else else