* lib/regexec.c (pop_fail_stack): If the stack is empty, return -1 instead of indulging in undefined behavior. This simplifies callers, and avoids undefined behavior in some cases (see glibc bug 11053, though this change does not fix that overall bug). --- ChangeLog | 6 ++++++ lib/regexec.c | 30 ++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/ChangeLog b/ChangeLog index fef04a89c..6fcd5819f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2021-02-05 Paul Eggert <egg...@cs.ucla.edu> + regex: avoid undefined behavior + * lib/regexec.c (pop_fail_stack): If the stack is empty, return -1 + instead of indulging in undefined behavior. This simplifies + callers, and avoids undefined behavior in some cases (see glibc + bug 11053, though this change does not fix that overall bug). + regex: improve comments * lib/regexec.c: Add and correct comments about return values. diff --git a/lib/regexec.c b/lib/regexec.c index fa413dfd5..f982e3aba 100644 --- a/lib/regexec.c +++ b/lib/regexec.c @@ -1346,13 +1346,15 @@ static Idx pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) { + if (fs == NULL || fs->num == 0) + return -1; Idx num = --fs->num; - DEBUG_ASSERT (num >= 0); *pidx = fs->stack[num].idx; memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); re_node_set_free (eps_via_nodes); re_free (fs->stack[num].regs); *eps_via_nodes = fs->stack[num].eps_via_nodes; + DEBUG_ASSERT (0 <= fs->stack[num].node); return fs->stack[num].node; } @@ -1411,25 +1413,22 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) { Idx reg_idx; + cur_node = -1; if (fs) { for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) - break; - if (reg_idx == nmatch) - { - re_node_set_free (&eps_via_nodes); - regmatch_list_free (&prev_match); - return free_fail_stack_return (fs); - } - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); + { + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + break; + } } - else + if (cur_node < 0) { re_node_set_free (&eps_via_nodes); regmatch_list_free (&prev_match); - return REG_NOERROR; + return free_fail_stack_return (fs); } } @@ -1446,13 +1445,12 @@ set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, free_fail_stack_return (fs); return REG_ESPACE; } - if (fs) - cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, - &eps_via_nodes); - else + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, &eps_via_nodes); + if (cur_node < 0) { re_node_set_free (&eps_via_nodes); regmatch_list_free (&prev_match); + free_fail_stack_return (fs); return REG_NOMATCH; } } -- 2.27.0