]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
regex: fix some leaks when pattern compilation fails
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 6 Jun 2025 01:52:33 +0000 (18:52 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 6 Jun 2025 02:01:18 +0000 (19:01 -0700)
Problem reported by Alec Brown in:
https://lists.gnu.org/r/bug-gnulib/2025-06/msg00040.html
* lib/regcomp.c (create_initial_state, calc_eclosure_iter):
Fix some memory leaks when these functions fail.

ChangeLog
lib/regcomp.c

index 2fdc7fb4c021c3bd64491b221e454d13bc05928b..e811cb496d7cf03682c15034f601bb9cc87f452b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-06-05  Paul Eggert  <eggert@cs.ucla.edu>
+
+       regex: fix some leaks when pattern compilation fails
+       Problem reported by Alec Brown in:
+       https://lists.gnu.org/r/bug-gnulib/2025-06/msg00040.html
+       * lib/regcomp.c (create_initial_state, calc_eclosure_iter):
+       Fix some memory leaks when these functions fail.
+
 2025-06-05  Bruno Haible  <bruno@clisp.org>
 
        unictype/base, uninorm/base, etc.: Support shared libraries on MSVC.
index a23f289d7a1292b43d2c432057efdb48e268bc42..41157e5c3a6a471c97deac4aea33f2480c37c07f 100644 (file)
@@ -1001,21 +1001,25 @@ create_initial_state (re_dfa_t *dfa)
            Idx dest_idx = dfa->edests[node_idx].elems[0];
            if (!re_node_set_contains (&init_nodes, dest_idx))
              {
-               reg_errcode_t merge_err
+               err
                   = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
-               if (merge_err != REG_NOERROR)
-                 return merge_err;
+               if (err != REG_NOERROR)
+                 break;
                i = 0;
              }
          }
       }
 
   /* It must be the first time to invoke acquire_state.  */
-  dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
-  /* We don't check ERR here, since the initial state must not be NULL.  */
+  dfa->init_state
+    = (err == REG_NOERROR
+       ? re_acquire_state_context (&err, dfa, &init_nodes, 0)
+       : NULL);
   if (__glibc_unlikely (dfa->init_state == NULL))
-    return err;
-  if (dfa->init_state->has_constraint)
+    {
+      /* Don't check ERR here, as the initial state must not be null.  */
+    }
+  else if (dfa->init_state->has_constraint)
     {
       dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
                                                       CONTEXT_WORD);
@@ -1025,17 +1029,13 @@ create_initial_state (re_dfa_t *dfa)
                                                         &init_nodes,
                                                         CONTEXT_NEWLINE
                                                         | CONTEXT_BEGBUF);
-      if (__glibc_unlikely (dfa->init_state_word == NULL
-                           || dfa->init_state_nl == NULL
-                           || dfa->init_state_begbuf == NULL))
-       return err;
     }
   else
     dfa->init_state_word = dfa->init_state_nl
       = dfa->init_state_begbuf = dfa->init_state;
 
   re_node_set_free (&init_nodes);
-  return REG_NOERROR;
+  return err;
 }
 \f
 /* If it is possible to do searching in single byte encoding instead of UTF-8
@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
     {
       err = duplicate_node_closure (dfa, node, node, node,
                                    dfa->nodes[node].constraint);
-      if (__glibc_unlikely (err != REG_NOERROR))
-       return err;
     }
 
   /* Expand each epsilon destination nodes.  */
-  if (IS_EPSILON_NODE(dfa->nodes[node].type))
+  if (__glibc_likely (err == REG_NOERROR)
+      && IS_EPSILON_NODE (dfa->nodes[node].type))
     for (i = 0; i < dfa->edests[node].nelem; ++i)
       {
        re_node_set eclosure_elem;
@@ -1700,14 +1699,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
          {
            err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false);
            if (__glibc_unlikely (err != REG_NOERROR))
-             return err;
+             break;
          }
        else
          eclosure_elem = dfa->eclosures[edest];
        /* Merge the epsilon closure of 'edest'.  */
        err = re_node_set_merge (&eclosure, &eclosure_elem);
        if (__glibc_unlikely (err != REG_NOERROR))
-         return err;
+         break;
        /* If the epsilon closure of 'edest' is incomplete,
           the epsilon closure of this node is also incomplete.  */
        if (dfa->eclosures[edest].nelem == 0)
@@ -1717,12 +1716,18 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
          }
       }
 
-  if (incomplete && !root)
-    dfa->eclosures[node].nelem = 0;
+  if (err != REG_NOERROR)
+    re_node_set_free (&eclosure);
   else
-    dfa->eclosures[node] = eclosure;
-  *new_set = eclosure;
-  return REG_NOERROR;
+    {
+      if (incomplete && !root)
+       dfa->eclosures[node].nelem = 0;
+      else
+       dfa->eclosures[node] = eclosure;
+      *new_set = eclosure;
+    }
+
+  return err;
 }
 \f
 /* Functions for token which are used in the parser.  */