Store return codes in match_data.

This makes match_data->rc after a call to pcre2_match, pcre2_jit_match, and
pcre2_dfa_match nire reliable, so that pcre2_substitute with
PCRE2_SUBSTITUTE_MATCHED can abort early.

(cherry picked from commit 1796fb2614a05eca4e67021a09f1b0c2a8acac4d)

Co-authored-by: Nicholas Wilson <nicholas@nicholaswilson.me.uk>
diff --git a/src/pcre2_dfa_match.c b/src/pcre2_dfa_match.c
index d82679b..ef5c6b9 100644
--- a/src/pcre2_dfa_match.c
+++ b/src/pcre2_dfa_match.c
@@ -3393,9 +3393,11 @@
 
 /* Plausibility checks */
 
-if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
-if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
-  return PCRE2_ERROR_NULL;
+if (match_data == NULL) return PCRE2_ERROR_NULL;
+if (re == NULL || subject == NULL || workspace == NULL)
+  { rc = PCRE2_ERROR_NULL; goto EXIT; }
+if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0)
+  { rc = PCRE2_ERROR_BADOPTION; goto EXIT; }
 
 if (length == PCRE2_ZERO_TERMINATED)
   {
@@ -3403,30 +3405,31 @@
   was_zero_terminated = 1;
   }
 
-if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
-if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+if (wscount < 20) { rc = PCRE2_ERROR_DFA_WSSIZE; goto EXIT; }
+if (start_offset > length) { rc = PCRE2_ERROR_BADOFFSET; goto EXIT; }
 
 /* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same
 time. */
 
 if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
    ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
-  return PCRE2_ERROR_BADOPTION;
+  { rc = PCRE2_ERROR_BADOPTION; goto EXIT; }
 
 /* Invalid UTF support is not available for DFA matching. */
 
 if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0)
-  return PCRE2_ERROR_DFA_UINVALID_UTF;
+  { rc = PCRE2_ERROR_DFA_UINVALID_UTF; goto EXIT; }
 
 /* Check that the first field in the block is the magic number. If it is not,
 return with PCRE2_ERROR_BADMAGIC. */
 
-if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+if (re->magic_number != MAGIC_NUMBER)
+  { rc = PCRE2_ERROR_BADMAGIC; goto EXIT; }
 
 /* Check the code unit width. */
 
 if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
-  return PCRE2_ERROR_BADMODE;
+  { rc = PCRE2_ERROR_BADMODE; goto EXIT; }
 
 /* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
 options variable for this function. Users of PCRE2 who are not calling the
@@ -3452,8 +3455,8 @@
 if ((options & PCRE2_DFA_RESTART) != 0)
   {
   if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 ||
-    workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK))
-      return PCRE2_ERROR_DFA_BADRESTART;
+      workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK))
+    { rc = PCRE2_ERROR_DFA_BADRESTART; goto EXIT; }
   }
 
 /* Set some local values */
@@ -3501,7 +3504,7 @@
   if (mcontext->offset_limit != PCRE2_UNSET)
     {
     if ((re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
-      return PCRE2_ERROR_BADOFFSETLIMIT;
+      { rc = PCRE2_ERROR_BADOFFSETLIMIT; goto EXIT; }
     bumpalong_limit = subject + mcontext->offset_limit;
     }
   mb->callout = mcontext->callout;
@@ -3571,7 +3574,8 @@
   /* LCOV_EXCL_START */
   default:
   PCRE2_DEBUG_UNREACHABLE();
-  return PCRE2_ERROR_INTERNAL;
+  rc = PCRE2_ERROR_INTERNAL;
+  goto EXIT;
   /* LCOV_EXCL_STOP */
   }
 
@@ -3593,7 +3597,7 @@
 #if PCRE2_CODE_UNIT_WIDTH != 32
     unsigned int i;
     if (start_match < end_subject && NOT_FIRSTCU(*start_match))
-      return PCRE2_ERROR_BADUTFOFFSET;
+      { rc = PCRE2_ERROR_BADUTFOFFSET; goto EXIT; }
     for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
       {
       check_subject--;
@@ -3614,12 +3618,12 @@
   /* Validate the relevant portion of the subject. After an error, adjust the
   offset to be an absolute offset in the whole string. */
 
-  match_data->rc = PRIV(valid_utf)(check_subject,
+  rc = PRIV(valid_utf)(check_subject,
     length - (PCRE2_SIZE)(check_subject - subject), &(match_data->startchar));
-  if (match_data->rc != 0)
+  if (rc != 0)
     {
     match_data->startchar += (PCRE2_SIZE)(check_subject - subject);
-    return match_data->rc;
+    goto EXIT;
     }
   }
 #endif  /* SUPPORT_UNICODE */
@@ -4047,14 +4051,13 @@
     match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject);
     match_data->rightchar = (PCRE2_SIZE)(mb->last_used_ptr - subject);
     match_data->startchar = (PCRE2_SIZE)(start_match - subject);
-    match_data->rc = rc;
 
     if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
       {
       length = CU2BYTES(length + was_zero_terminated);
       match_data->subject = match_data->memctl.malloc(length,
         match_data->memctl.memory_data);
-      if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY;
+      if (match_data->subject == NULL) { rc = PCRE2_ERROR_NOMEMORY; goto EXIT; }
       memcpy((void *)match_data->subject, subject, length);
       match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
       }
@@ -4105,6 +4108,7 @@
   mb->memctl.free(next, mb->memctl.memory_data);
   }
 
+match_data->rc = rc;
 return rc;
 }
 
diff --git a/src/pcre2_jit_match_inc.h b/src/pcre2_jit_match_inc.h
index 81cd9cc..d3aea6c 100644
--- a/src/pcre2_jit_match_inc.h
+++ b/src/pcre2_jit_match_inc.h
@@ -99,9 +99,8 @@
 (void)length;
 (void)start_offset;
 (void)options;
-(void)match_data;
 (void)mcontext;
-return PCRE2_ERROR_JIT_BADOPTION;
+return match_data->rc = PCRE2_ERROR_JIT_BADOPTION;
 
 #else  /* SUPPORT_JIT */
 
@@ -124,7 +123,7 @@
   index = 1;
 
 if (functions == NULL || functions->executable_funcs[index] == NULL)
-  return PCRE2_ERROR_JIT_BADOPTION;
+  return match_data->rc = PCRE2_ERROR_JIT_BADOPTION;
 
 /* Sanity checks should be handled by pcre2_match. */
 arguments.str = subject + start_offset;
diff --git a/src/pcre2_match.c b/src/pcre2_match.c
index 047d254..ec40660 100644
--- a/src/pcre2_match.c
+++ b/src/pcre2_match.c
@@ -7012,9 +7012,11 @@
 
 /* Plausibility checks */
 
-if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
-if (code == NULL || subject == NULL || match_data == NULL)
-  return PCRE2_ERROR_NULL;
+if (match_data == NULL) return PCRE2_ERROR_NULL;
+if (code == NULL || subject == NULL)
+  return match_data->rc = PCRE2_ERROR_NULL;
+if ((options & ~PUBLIC_MATCH_OPTIONS) != 0)
+  return match_data->rc = PCRE2_ERROR_BADOPTION;
 
 start_match = subject + start_offset;
 req_cu_ptr = start_match - 1;
@@ -7025,16 +7027,17 @@
   }
 true_end_subject = end_subject = subject + length;
 
-if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+if (start_offset > length) return match_data->rc = PCRE2_ERROR_BADOFFSET;
 
 /* Check that the first field in the block is the magic number. */
 
-if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+if (re->magic_number != MAGIC_NUMBER)
+  return match_data->rc = PCRE2_ERROR_BADMAGIC;
 
 /* Check the code unit width. */
 
 if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
-  return PCRE2_ERROR_BADMODE;
+  return match_data->rc = PCRE2_ERROR_BADMODE;
 
 /* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
 options variable for this function. Users of PCRE2 who are not calling the
@@ -7081,14 +7084,14 @@
 
 if (mb->partial != 0 &&
    ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
-  return PCRE2_ERROR_BADOPTION;
+  return match_data->rc = PCRE2_ERROR_BADOPTION;
 
 /* It is an error to set an offset limit without setting the flag at compile
 time. */
 
 if (mcontext != NULL && mcontext->offset_limit != PCRE2_UNSET &&
      (re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
-  return PCRE2_ERROR_BADOFFSETLIMIT;
+  return match_data->rc = PCRE2_ERROR_BADOFFSETLIMIT;
 
 /* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT,
 free the memory that was obtained. Set the field to NULL for no match cases. */
@@ -7128,11 +7131,11 @@
 #if PCRE2_CODE_UNIT_WIDTH != 32
     if (start_match < end_subject && NOT_FIRSTCU(*start_match))
       {
-      if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET;
+      if (start_offset > 0) return match_data->rc = PCRE2_ERROR_BADUTFOFFSET;
 #if PCRE2_CODE_UNIT_WIDTH == 8
-      return PCRE2_ERROR_UTF8_ERR20;  /* Isolated 0x80 byte */
+      return match_data->rc = PCRE2_ERROR_UTF8_ERR20;  /* Isolated 0x80 byte */
 #else
-      return PCRE2_ERROR_UTF16_ERR3;  /* Isolated low surrogate */
+      return match_data->rc = PCRE2_ERROR_UTF16_ERR3;  /* Isolated low surrogate */
 #endif
       }
 #endif  /* WIDTH != 32 */
@@ -7167,12 +7170,12 @@
     /* Validate the relevant portion of the subject. Adjust the offset of an
     invalid code point to be an absolute offset in the whole string. */
 
-    match_data->rc = PRIV(valid_utf)(start_match,
+    rc = PRIV(valid_utf)(start_match,
       length - (start_match - subject), &(match_data->startchar));
-    if (match_data->rc != 0)
+    if (rc != 0)
       {
       match_data->startchar += start_match - subject;
-      return match_data->rc;
+      return match_data->rc = rc;
       }
     jit_checked_utf = TRUE;
     }
@@ -7190,7 +7193,8 @@
       length = CU2BYTES(length + was_zero_terminated);
       match_data->subject = match_data->memctl.malloc(length,
         match_data->memctl.memory_data);
-      if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY;
+      if (match_data->subject == NULL)
+        return match_data->rc = PCRE2_ERROR_NOMEMORY;
       memcpy((void *)match_data->subject, subject, length);
       match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
       }
@@ -7256,11 +7260,11 @@
     }
   else if (start_match < end_subject && NOT_FIRSTCU(*start_match))
     {
-    if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET;
+    if (start_offset > 0) return match_data->rc = PCRE2_ERROR_BADUTFOFFSET;
 #if PCRE2_CODE_UNIT_WIDTH == 8
-    return PCRE2_ERROR_UTF8_ERR20;  /* Isolated 0x80 byte */
+    return match_data->rc = PCRE2_ERROR_UTF8_ERR20;  /* Isolated 0x80 byte */
 #else
-    return PCRE2_ERROR_UTF16_ERR3;  /* Isolated low surrogate */
+    return match_data->rc = PCRE2_ERROR_UTF16_ERR3;  /* Isolated low surrogate */
 #endif
     }
 #endif  /* WIDTH != 32 */
@@ -7308,10 +7312,10 @@
 
   for (;;)
     {
-    match_data->rc = PRIV(valid_utf)(mb->check_subject,
+    rc = PRIV(valid_utf)(mb->check_subject,
       length - (mb->check_subject - subject), &(match_data->startchar));
 
-    if (match_data->rc == 0) break;   /* Valid UTF string */
+    if (rc == 0) break;   /* Valid UTF string */
 
     /* Invalid UTF string. Adjust the offset to be an absolute offset in the
     whole string. If we are handling invalid UTF strings, set end_subject to
@@ -7319,7 +7323,7 @@
     Otherwise return the error. */
 
     match_data->startchar += mb->check_subject - subject;
-    if (!allow_invalid || match_data->rc > 0) return match_data->rc;
+    if (!allow_invalid || rc > 0) return match_data->rc = rc;
     end_subject = subject + match_data->startchar;
 
     /* If the end precedes start_match, it means there is invalid UTF in the
@@ -7436,7 +7440,7 @@
   /* LCOV_EXCL_START */
   default:
   PCRE2_DEBUG_UNREACHABLE();
-  return PCRE2_ERROR_INTERNAL;
+  return match_data->rc = PCRE2_ERROR_INTERNAL;
   /* LCOV_EXCL_STOP */
   }
 
@@ -7479,7 +7483,7 @@
 if (heapframes_size / 1024 > mb->heap_limit)
   {
   PCRE2_SIZE max_size = 1024 * mb->heap_limit;
-  if (max_size < frame_size) return PCRE2_ERROR_HEAPLIMIT;
+  if (max_size < frame_size) return match_data->rc = PCRE2_ERROR_HEAPLIMIT;
   heapframes_size = max_size;
   }
 
@@ -7495,7 +7499,7 @@
   if (match_data->heapframes == NULL)
     {
     match_data->heapframes_size = 0;
-    return PCRE2_ERROR_NOMEMORY;
+    return match_data->rc = PCRE2_ERROR_NOMEMORY;
     }
   match_data->heapframes_size = heapframes_size;
   }
@@ -8150,7 +8154,8 @@
     length = CU2BYTES(length + was_zero_terminated);
     match_data->subject = match_data->memctl.malloc(length,
       match_data->memctl.memory_data);
-    if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY;
+    if (match_data->subject == NULL)
+      return match_data->rc = PCRE2_ERROR_NOMEMORY;
     memcpy((void *)match_data->subject, subject, length);
     match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
     }