[php-src] PHP-8.3: Backport PCRE2 security fixes to bundled 10.40

From: Date: Mon, 12 Oct 2026 07:54:08 +0000
Subject: [php-src] PHP-8.3: Backport PCRE2 security fixes to bundled 10.40
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-142197@lists.php.net to get a copy of this message
Author: Alexandre Daubois (alexandre-daubois) Date: 2026-10-12T09:37:31+02:00 Commit: https://github.com/php/php-src/commit/1e8a51d545d92084e1d354d81030e30cc8a3e3a0 Raw diff: https://github.com/php/php-src/commit/1e8a51d545d92084e1d354d81030e30cc8a3e3a0.diff 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. Changed paths: M NEWS M ext/pcre/pcre2lib/pcre2_compile.c M ext/pcre/pcre2lib/pcre2_convert.c M ext/pcre/pcre2lib/pcre2_dfa_match.c M ext/pcre/pcre2lib/pcre2_extuni.c M ext/pcre/pcre2lib/pcre2_internal.h M ext/pcre/pcre2lib/pcre2_jit_compile.c M ext/pcre/pcre2lib/pcre2_jit_match.c M ext/pcre/pcre2lib/pcre2_jit_misc.c M ext/pcre/pcre2lib/pcre2_jit_simd_inc.h M ext/pcre/pcre2lib/pcre2_match.c M ext/pcre/pcre2lib/pcre2_substring.c Diff: diff --git a/NEWS b/NEWS index 91bd9e2da7c4..94580e7c7fe5 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 de259c9c4057..ec68d3850c63 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 d45b6fee9744..f336be4586ad 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 d29130f2d0c0..c52bd6805cc9 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 b23946b0d16e..b0e73350e72a 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 fe7a0e005a0e..21b673e56df8 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 79b23d0f6566..5de96673ad5b 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 1ab3af073e6a..55b68d7aad68 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 e57afad065ba..6233689727c3 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 d99cfc5ce460..46083f8e4d40 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 e603cb24992e..e36ecd02585e 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 ddf5774e1501..a52f542e72b6 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));

« previous php.cvs (#142197) next »