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;
}