Commit 1e8a51d545d for php
commit 1e8a51d545d92084e1d354d81030e30cc8a3e3a0
Author: Alexandre Daubois <alex.daubois@gmail.com>
Date: Tue Sep 29 11:59:15 2026 +0200
Backport PCRE2 security fixes to bundled 10.40
Apply the upstream backports listed for PCRE2 10.40 in SUPPORT-LIFECYCLE.md through 10.49 (GHSA-2p8c-ff85-vh9x, GHSA-q8g2-wprr-34m9, GHSA-9qww-pwc4-77qq, GHSA-fmgr-6ggq-9859, GHSA-3r4p-g7gg-ppmf, GHSA-r9hj-j2rw-4q3m), adapted to 10.40 where the patched code differs. Disable the legacy ARM64 NEON SIMD scanning for GHSA-43gg-c3xx-7w7g, as the upstream fix is a rewrite with no small backport.
Closes GH-24011.
diff --git a/NEWS b/NEWS
index 91bd9e2da7c..94580e7c7fe 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,12 @@ PHP NEWS
php_openssl_matches_wildcard_name() on crafted server certificate wildcard
CN). (CVE-2026-91767) (Jakub Zelenka)
+- PCRE:
+ . Applied security fixes to bundled PCRE2 10.40 and disabled its legacy
+ ARM64 SIMD optimization (GHSA-2p8c-ff85-vh9x, GHSA-q8g2-wprr-34m9,
+ GHSA-9qww-pwc4-77qq, GHSA-fmgr-6ggq-9859, GHSA-3r4p-g7gg-ppmf,
+ GHSA-r9hj-j2rw-4q3m, and GHSA-43gg-c3xx-7w7g). (alexandre-daubois)
+
- Phar:
. Fixed GHSA-j3wh-g957-2m85 (Integer overflow in phar_tar_number() allowing
TAR archive entry injection). (CVE-2026-6103) (Jakub Zelenka)
diff --git a/ext/pcre/pcre2lib/pcre2_compile.c b/ext/pcre/pcre2lib/pcre2_compile.c
index de259c9c405..ec68d3850c6 100644
--- a/ext/pcre/pcre2lib/pcre2_compile.c
+++ b/ext/pcre/pcre2lib/pcre2_compile.c
@@ -5521,7 +5521,8 @@ for (;; pptr++)
if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
{
- if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
+ if (*lengthptr > OFLOW_MAX ||
+ OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
{
*errorcodeptr = ERR20; /* Integer overflow */
return 0;
@@ -8305,7 +8306,8 @@ for (;;)
*reqcuflagsptr = reqcuflags;
if (lengthptr != NULL)
{
- if (OFLOW_MAX - *lengthptr < length)
+ if (*lengthptr > MAX_PATTERN_SIZE ||
+ MAX_PATTERN_SIZE - *lengthptr < length)
{
*errorcodeptr = ERR20;
return 0;
@@ -8328,6 +8330,19 @@ for (;;)
{
code = *codeptr + 1 + LINK_SIZE + skipunits;
length += 1 + LINK_SIZE;
+
+ /* Move the accumulated length into *lengthptr, providing the next call to
+ compile_branch with as much space in &length and &code as the first did. */
+
+ if (*lengthptr > MAX_PATTERN_SIZE ||
+ MAX_PATTERN_SIZE - *lengthptr < length)
+ {
+ *errorcodeptr = ERR20;
+ cb->erroroffset = 0;
+ return 0;
+ }
+ *lengthptr += length;
+ length = 0;
}
else
{
@@ -10243,9 +10258,29 @@ the compiled pattern and names table. Integer overflow should no longer be
possible because nowadays we limit the maximum value of cb.names_found and
cb.name_entry_size. */
-re_blocksize = sizeof(pcre2_real_code) +
- CU2BYTES(length +
+re_blocksize = CU2BYTES(
(PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size);
+
+if (length > BYTES2CU(PCRE2_SIZE_MAX - re_blocksize))
+ {
+ /* Given the current value of 2^30 for MAX_PATTERN_SIZE, this block is only
+ reachable when both PCRE2_CODE_UNIT_WIDTH >= 16 and sizeof(size_t) is
+ 32 bits. */
+ errorcode = ERR20;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+
+re_blocksize += CU2BYTES(length);
+
+if (sizeof(pcre2_real_code) > PCRE2_SIZE_MAX - re_blocksize)
+ {
+ errorcode = ERR20;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+
+re_blocksize += sizeof(pcre2_real_code);
re = (pcre2_real_code *)
ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
if (re == NULL)
diff --git a/ext/pcre/pcre2lib/pcre2_convert.c b/ext/pcre/pcre2lib/pcre2_convert.c
index d45b6fee974..f336be4586a 100644
--- a/ext/pcre/pcre2lib/pcre2_convert.c
+++ b/ext/pcre/pcre2lib/pcre2_convert.c
@@ -1143,9 +1143,12 @@ for (i = 0; i < 2; i++)
/* Allocate memory for the buffer, with hidden space for an allocator at
the start. The next time round the loop runs the conversion for real. */
- allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
- (*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext);
- if (allocated == NULL) return PCRE2_ERROR_NOMEMORY;
+ if (*bufflenptr > ((PCRE2_SIZE_MAX - sizeof(pcre2_memctl)) /
+ CU2BYTES(1)) - 1 ||
+ (allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+ CU2BYTES(*bufflenptr + 1),
+ (pcre2_memctl *)ccontext)) == NULL)
+ return PCRE2_ERROR_NOMEMORY;
*buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl));
use_buffer = *buffptr;
diff --git a/ext/pcre/pcre2lib/pcre2_dfa_match.c b/ext/pcre/pcre2lib/pcre2_dfa_match.c
index d29130f2d0c..c52bd6805cc 100644
--- a/ext/pcre/pcre2lib/pcre2_dfa_match.c
+++ b/ext/pcre/pcre2lib/pcre2_dfa_match.c
@@ -397,8 +397,8 @@ return (mb->callout)(cb, mb->callout_data);
/* This function is called when internal_dfa_match() is about to be called
recursively and there is insufficient working space left in the current
-workspace block. If there's an existing next block, use it; otherwise get a new
-block unless the heap limit is reached.
+workspace block. If there's a sufficiently large next block, use it; get a new
+block unless the heap limit is (or has been) reached.
Arguments:
rwsptr pointer to block pointer (updated)
@@ -414,9 +414,17 @@ more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb)
{
RWS_anchor *rws = *rwsptr;
RWS_anchor *new;
+uint32_t requested;
+
+requested = RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE;
if (rws->next != NULL)
{
+ /* Although the initial block is large, and subsequent ones try to double, the
+ heap limit may cause the last one to be smaller; in this case, we have already
+ hit the heap limit and allocating a larger block will not be possible. */
+ if (rws->next->size < requested)
+ return PCRE2_ERROR_HEAPLIMIT;
new = rws->next;
}
@@ -426,14 +434,30 @@ overflow. */
else
{
- uint32_t newsize = (rws->size >= UINT32_MAX/2)? UINT32_MAX/2 : rws->size * 2;
+ uint32_t newsize = (rws->size >= (UINT32_MAX/sizeof(int))/2)?
+ UINT32_MAX/sizeof(int) : rws->size * 2;
uint32_t newsizeK = newsize/(1024/sizeof(int));
- if (newsizeK + mb->heap_used > mb->heap_limit)
- newsizeK = (uint32_t)(mb->heap_limit - mb->heap_used);
- newsize = newsizeK*(1024/sizeof(int));
+ /* Clamp the allocation to the remaining heap allowance with care for overflows */
+
+ if (mb->heap_used >= mb->heap_limit)
+ {
+ newsize = 0;
+ newsizeK = 0;
+ }
+ else
+ {
+ PCRE2_SIZE availableK = mb->heap_limit - mb->heap_used;
+ /* newsize always capped at UINT32_MAX/sizeof(int), so newsizeK also capped;
+ and - if availableK is smaller - then multiplication to form newsize is safe */
+ if (newsizeK > availableK)
+ {
+ newsize = (uint32_t)(availableK*(1024/sizeof(int)));
+ newsizeK = availableK;
+ }
+ }
- if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
+ if (newsize < requested)
return PCRE2_ERROR_HEAPLIMIT;
new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
if (new == NULL) return PCRE2_ERROR_NOMEMORY;
diff --git a/ext/pcre/pcre2lib/pcre2_extuni.c b/ext/pcre/pcre2lib/pcre2_extuni.c
index b23946b0d16..b0e73350e72 100644
--- a/ext/pcre/pcre2lib/pcre2_extuni.c
+++ b/ext/pcre/pcre2lib/pcre2_extuni.c
@@ -57,12 +57,12 @@ support, because some compilers do not like functionless source files. */
#ifndef SUPPORT_UNICODE
PCRE2_SPTR
-PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR check_subject,
PCRE2_SPTR end_subject, BOOL utf, int *xcount)
{
(void)c;
(void)eptr;
-(void)start_subject;
+(void)check_subject;
(void)end_subject;
(void)utf;
(void)xcount;
@@ -79,7 +79,7 @@ return NULL;
Arguments:
c the first character
eptr pointer to next character
- start_subject pointer to start of subject
+ check_subject pointer to start of validated subject
end_subject pointer to end of subject
utf TRUE if in UTF mode
xcount pointer to count of additional characters,
@@ -89,7 +89,7 @@ Returns: pointer after the end of the sequence
*/
PCRE2_SPTR
-PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR check_subject,
PCRE2_SPTR end_subject, BOOL utf, int *xcount)
{
int lgb = UCD_GRAPHBREAK(c);
@@ -113,7 +113,7 @@ while (eptr < end_subject)
/* bptr is pointing to the left-hand character */
- while (bptr > start_subject)
+ while (bptr > check_subject)
{
bptr--;
if (utf)
diff --git a/ext/pcre/pcre2lib/pcre2_internal.h b/ext/pcre/pcre2lib/pcre2_internal.h
index fe7a0e005a0..21b673e56df 100644
--- a/ext/pcre/pcre2lib/pcre2_internal.h
+++ b/ext/pcre/pcre2lib/pcre2_internal.h
@@ -1991,6 +1991,7 @@ is available. */
#define _pcre2_is_newline PCRE2_SUFFIX(_pcre2_is_newline_)
#define _pcre2_jit_free_rodata PCRE2_SUFFIX(_pcre2_jit_free_rodata_)
#define _pcre2_jit_free PCRE2_SUFFIX(_pcre2_jit_free_)
+#define _pcre2_jit_check_exec PCRE2_SUFFIX(_pcre2_jit_check_exec_)
#define _pcre2_jit_get_size PCRE2_SUFFIX(_pcre2_jit_get_size_)
#define _pcre2_jit_get_target PCRE2_SUFFIX(_pcre2_jit_get_target_)
#define _pcre2_memctl_malloc PCRE2_SUFFIX(_pcre2_memctl_malloc_)
@@ -2018,6 +2019,7 @@ extern BOOL _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
uint32_t *, BOOL);
extern void _pcre2_jit_free_rodata(void *, void *);
extern void _pcre2_jit_free(void *, pcre2_memctl *);
+extern BOOL _pcre2_jit_check_exec(void *, uint32_t);
extern size_t _pcre2_jit_get_size(void *);
const char * _pcre2_jit_get_target(void);
extern void * _pcre2_memctl_malloc(size_t, pcre2_memctl *);
diff --git a/ext/pcre/pcre2lib/pcre2_jit_compile.c b/ext/pcre/pcre2lib/pcre2_jit_compile.c
index 79b23d0f656..5de96673ad5 100644
--- a/ext/pcre/pcre2lib/pcre2_jit_compile.c
+++ b/ext/pcre/pcre2lib/pcre2_jit_compile.c
@@ -97,7 +97,7 @@ Fast, but limited size. */
/* Growth rate for stack allocated by the OS. Should be the multiply
of page size. */
-#define STACK_GROWTH_RATE 8192
+#define STACK_GROWTH_RATE (sljit_sw)8192
/* Enable to check that the allocation could destroy temporaries. */
#if defined SLJIT_DEBUG && SLJIT_DEBUG
@@ -438,6 +438,8 @@ typedef struct compiler_common {
BOOL local_quit_available;
/* Currently in a positive assertion. */
BOOL in_positive_assertion;
+ /* More than STACK_GROWTH_RATE / 2 stack memory is allocated. */
+ BOOL large_stack_allocation;
/* Newline control. */
int nltype;
sljit_u32 nlmax;
@@ -3144,6 +3146,8 @@ static SLJIT_INLINE void allocate_stack(compiler_common *common, int size)
DEFINE_COMPILER;
SLJIT_ASSERT(size > 0);
+if (size > (STACK_GROWTH_RATE / ((sljit_s32)sizeof(sljit_sw) * 2)))
+ common->large_stack_allocation = TRUE;
OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
#ifdef DESTROY_REGISTERS
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
@@ -14193,7 +14197,20 @@ SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
-OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE);
+if (common->large_stack_allocation)
+ {
+ SLJIT_COMPILE_ASSERT((STACK_GROWTH_RATE & (STACK_GROWTH_RATE - 1)) == 0, stack_growth_must_be_power_of_2);
+ // Negative difference. The positive difference would also use the same amount
+ // of operations, but the last subtraction emits several instructions on x86.
+ OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_TOP, 0, STACK_LIMIT, 0);
+ // Minimum extra space after allocation.
+ OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, (STACK_GROWTH_RATE / 2));
+ // Rounds down negative numbers.
+ OP2(SLJIT_AND, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, ~(STACK_GROWTH_RATE - 1));
+ OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, STACK_LIMIT, 0);
+ }
+else
+ OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE);
OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack));
OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0);
diff --git a/ext/pcre/pcre2lib/pcre2_jit_match.c b/ext/pcre/pcre2lib/pcre2_jit_match.c
index 1ab3af073e6..55b68d7aad6 100644
--- a/ext/pcre/pcre2lib/pcre2_jit_match.c
+++ b/ext/pcre/pcre2lib/pcre2_jit_match.c
@@ -112,6 +112,7 @@ jit_arguments arguments;
int rc;
int index = 0;
+/* The same check is performed by jit_check_exec(). */
if ((options & PCRE2_PARTIAL_HARD) != 0)
index = 2;
else if ((options & PCRE2_PARTIAL_SOFT) != 0)
@@ -120,6 +121,16 @@ else if ((options & PCRE2_PARTIAL_SOFT) != 0)
if (functions == NULL || functions->executable_funcs[index] == NULL)
return PCRE2_ERROR_JIT_BADOPTION;
+/* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT,
+free the memory that was obtained. */
+
+if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
+ {
+ match_data->memctl.free((void *)match_data->subject,
+ match_data->memctl.memory_data);
+ match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT;
+ }
+
/* Sanity checks should be handled by pcre2_match. */
arguments.str = subject + start_offset;
arguments.begin = subject;
diff --git a/ext/pcre/pcre2lib/pcre2_jit_misc.c b/ext/pcre/pcre2lib/pcre2_jit_misc.c
index e57afad065b..6233689727c 100644
--- a/ext/pcre/pcre2lib/pcre2_jit_misc.c
+++ b/ext/pcre/pcre2lib/pcre2_jit_misc.c
@@ -212,6 +212,32 @@ return sljit_get_platform_name();
}
+/*************************************************
+* Checks function compilation *
+*************************************************/
+
+BOOL
+PRIV(jit_check_exec)(void *executable_jit, uint32_t options)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+(void)options;
+return FALSE;
+#else /* SUPPORT_JIT */
+/* The same check is performed at the beginning of pcre2_jit_match(). */
+executable_functions *functions = (executable_functions *)executable_jit;
+int index = 0;
+
+if ((options & PCRE2_PARTIAL_HARD) != 0)
+ index = 2;
+else if ((options & PCRE2_PARTIAL_SOFT) != 0)
+ index = 1;
+
+return functions->executable_funcs[index] != NULL;
+#endif
+}
+
+
/*************************************************
* Get size of JIT code *
*************************************************/
diff --git a/ext/pcre/pcre2lib/pcre2_jit_simd_inc.h b/ext/pcre/pcre2lib/pcre2_jit_simd_inc.h
index d99cfc5ce46..46083f8e4d4 100644
--- a/ext/pcre/pcre2lib/pcre2_jit_simd_inc.h
+++ b/ext/pcre/pcre2lib/pcre2_jit_simd_inc.h
@@ -766,7 +766,7 @@ if (common->match_end_ptr != 0)
#endif /* SLJIT_CONFIG_X86 */
-#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 && (defined __ARM_NEON || defined __ARM_NEON__))
+#if 0
#include <arm_neon.h>
diff --git a/ext/pcre/pcre2lib/pcre2_match.c b/ext/pcre/pcre2lib/pcre2_match.c
index e603cb24992..e36ecd02585 100644
--- a/ext/pcre/pcre2lib/pcre2_match.c
+++ b/ext/pcre/pcre2lib/pcre2_match.c
@@ -2550,7 +2550,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject, utf,
NULL);
}
CHECK_PARTIAL();
@@ -2903,7 +2903,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject,
mb->end_subject, utf, NULL);
}
CHECK_PARTIAL();
@@ -3725,7 +3725,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject,
utf, NULL);
}
CHECK_PARTIAL();
@@ -4306,7 +4306,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
else
{
GETCHARINCTEST(fc, Feptr);
- Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+ Feptr = PRIV(extuni)(fc, Feptr, mb->check_subject, mb->end_subject,
utf, NULL);
}
CHECK_PARTIAL();
@@ -6327,10 +6327,6 @@ PCRE2_SPTR req_cu_ptr;
PCRE2_SPTR start_partial;
PCRE2_SPTR match_partial;
-#ifdef SUPPORT_JIT
-BOOL use_jit;
-#endif
-
/* This flag is needed even when Unicode is not supported for convenience
(it is used by the IS_NEWLINE macro). */
@@ -6340,9 +6336,6 @@ BOOL utf = FALSE;
BOOL ucp = FALSE;
BOOL allow_invalid;
uint32_t fragment_options = 0;
-#ifdef SUPPORT_JIT
-BOOL jit_checked_utf = FALSE;
-#endif
#endif /* SUPPORT_UNICODE */
PCRE2_SIZE frame_size;
@@ -6411,15 +6404,6 @@ options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
#undef FF
#undef OO
-/* If the pattern was successfully studied with JIT support, we will run the
-JIT executable instead of the rest of this function. Most options must be set
-at compile time for the JIT code to be usable. */
-
-#ifdef SUPPORT_JIT
-use_jit = (re->executable_jit != NULL &&
- (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0);
-#endif
-
/* Initialize UTF/UCP parameters. */
#ifdef SUPPORT_UNICODE
@@ -6465,16 +6449,22 @@ match_data->startchar = 0;
/* ============================= JIT matching ============================== */
-/* Prepare for JIT matching. Check a UTF string for validity unless no check is
-requested or invalid UTF can be handled. We check only the portion of the
-subject that might be be inspected during matching - from the offset minus the
-maximum lookbehind to the given length. This saves time when a small part of a
-large subject is being matched by the use of a starting offset. Note that the
-maximum lookbehind is a number of characters, not code units. */
+/* If the pattern was successfully studied with JIT support, we will run the
+JIT executable instead of the rest of this function. Most options must be set
+at compile time for the JIT code to be usable. */
#ifdef SUPPORT_JIT
-if (use_jit)
+if (re->executable_jit != NULL &&
+ (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0 &&
+ PRIV(jit_check_exec)(re->executable_jit, options))
{
+ /* Prepare for JIT matching. Check a UTF string for validity unless no check
+ is requested or invalid UTF can be handled. We check only the portion of the
+ subject that might be be inspected during matching - from the offset minus
+ the maximum lookbehind to the given length. This saves time when a small part
+ of a large subject is being matched by the use of a starting offset. Note that
+ the maximum lookbehind is a number of characters, not code units. */
+
#ifdef SUPPORT_UNICODE
if (utf && (options & PCRE2_NO_UTF_CHECK) == 0 && !allow_invalid)
{
@@ -6534,16 +6524,12 @@ if (use_jit)
match_data->startchar += start_match - subject;
return match_data->rc;
}
- jit_checked_utf = TRUE;
}
#endif /* SUPPORT_UNICODE */
- /* If JIT returns BADOPTION, which means that the selected complete or
- partial matching mode was not compiled, fall through to the interpreter. */
-
rc = pcre2_jit_match(code, subject, length, start_offset, options,
match_data, mcontext);
- if (rc != PCRE2_ERROR_JIT_BADOPTION)
+
{
if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
{
@@ -6568,12 +6554,8 @@ this. */
mb->check_subject = subject;
-/* If a UTF subject string was not checked for validity in the JIT code above,
-check it here, and handle support for invalid UTF strings. The check above
-happens only when invalid UTF is not supported and PCRE2_NO_CHECK_UTF is unset.
-If we get here in those circumstances, it means the subject string is valid,
-but for some reason JIT matching was not successful. There is no need to check
-the subject again.
+/* Check the validity of UTF subject strings. The check happens only when
+PCRE2_NO_CHECK_UTF is unset.
We check only the portion of the subject that might be be inspected during
matching - from the offset minus the maximum lookbehind to the given length.
@@ -6585,11 +6567,7 @@ Note also that support for invalid UTF forces a check, overriding the setting
of PCRE2_NO_CHECK_UTF. */
#ifdef SUPPORT_UNICODE
-if (utf &&
-#ifdef SUPPORT_JIT
- !jit_checked_utf &&
-#endif
- ((options & PCRE2_NO_UTF_CHECK) == 0 || allow_invalid))
+if (utf && ((options & PCRE2_NO_UTF_CHECK) == 0 || allow_invalid))
{
#if PCRE2_CODE_UNIT_WIDTH != 32
BOOL skipped_bad_start = FALSE;
diff --git a/ext/pcre/pcre2lib/pcre2_substring.c b/ext/pcre/pcre2lib/pcre2_substring.c
index ddf5774e150..a52f542e72b 100644
--- a/ext/pcre/pcre2lib/pcre2_substring.c
+++ b/ext/pcre/pcre2lib/pcre2_substring.c
@@ -214,9 +214,10 @@ PCRE2_SIZE size;
PCRE2_UCHAR *yield;
rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
if (rc < 0) return rc;
-yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
- (size + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data);
-if (yield == NULL) return PCRE2_ERROR_NOMEMORY;
+if (size > ((PCRE2_SIZE_MAX - sizeof(pcre2_memctl)) / CU2BYTES(1)) - 1 ||
+ (yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+ CU2BYTES(size + 1), (pcre2_memctl *)match_data)) == NULL)
+ return PCRE2_ERROR_NOMEMORY;
yield = (PCRE2_UCHAR *)(((char *)yield) + sizeof(pcre2_memctl));
memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2],
CU2BYTES(size));