diff --git a/DEPENDENCIES b/DEPENDENCIES index 8cbbe86c0..70c0dc21e 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -6,7 +6,7 @@ cmark-gfm https://github.com/github/cmark-gfm 587a12bb54d95ac37241377e6ddc93ea0e uritemplate-test https://github.com/uri-templates/uritemplate-test 1eb27ab4462b9e5819dc47db99044f5fd1fa9bc7 pyca-cryptography https://github.com/pyca/cryptography 9747d06e83764e7f1ea4c04daf134cb8f861700b wycheproof https://github.com/C2SP/wycheproof 6d7cccd0fcb1917368579adeeac10fe802f1b521 -pcre2 https://github.com/PCRE2Project/pcre2 pcre2-10.48-RC1 +pcre2 https://github.com/PCRE2Project/pcre2 pcre2-10.48 googlebenchmark https://github.com/google/benchmark 378fe693a1ef51500db21b11ff05a8018c5f0e55 libdeflate https://github.com/ebiggers/libdeflate v1.26 unicodetools https://github.com/unicode-org/unicodetools final-17.0-20250910 diff --git a/cmake/FindPCRE2.cmake b/cmake/FindPCRE2.cmake index 29e44e328..21756978b 100644 --- a/cmake/FindPCRE2.cmake +++ b/cmake/FindPCRE2.cmake @@ -146,6 +146,7 @@ if(NOT PCRE2_FOUND) target_compile_options(pcre2 PRIVATE /sdl-) target_compile_options(pcre2 PRIVATE /wd4127) target_compile_options(pcre2 PRIVATE /wd4244) + target_compile_options(pcre2 PRIVATE /wd4267) target_compile_options(pcre2 PRIVATE /wd4389) target_compile_options(pcre2 PRIVATE /wd4701) target_compile_options(pcre2 PRIVATE /wd4702) diff --git a/vendor/pcre2/src/pcre2_compile.c b/vendor/pcre2/src/pcre2_compile.c index 1081cf647..32cb32f65 100644 --- a/vendor/pcre2/src/pcre2_compile.c +++ b/vendor/pcre2/src/pcre2_compile.c @@ -6195,7 +6195,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 */ cb->erroroffset = 0; @@ -8802,7 +8803,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; @@ -8825,6 +8827,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 { @@ -10851,7 +10866,8 @@ if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */ #if defined SUPPORT_WIDE_CHARS PCRE2_ASSERT((cb.char_lists_size & 0x3) == 0); if (length > MAX_PATTERN_SIZE || - MAX_PATTERN_SIZE - length < (cb.char_lists_size / sizeof(PCRE2_UCHAR))) + BYTES2CU(cb.char_lists_size) > MAX_PATTERN_SIZE || + MAX_PATTERN_SIZE - length < BYTES2CU(cb.char_lists_size)) #else if (length > MAX_PATTERN_SIZE) #endif @@ -10876,11 +10892,36 @@ if (cb.char_lists_size != 0) /* Align to 32 bit first. This ensures the allocated area will also be 32 bit aligned. */ re_blocksize = (PCRE2_SIZE)CLIST_ALIGN_TO(re_blocksize, sizeof(uint32_t)); +#else + /* Already 32 bit aligned. */ #endif + + /* We have bounded the length and BYTES2CU(char_lists_size) to + MAX_PATTERN_SIZE units, however (with 32-bit code units) char_lists_size + in bytes could still be extremely close to (or greater than) SIZE_MAX, so + we require another overflow check. */ + + if (cb.char_lists_size > PCRE2_SIZE_MAX - re_blocksize) + { + errorcode = ERR20; + cb.erroroffset = 0; + goto HAD_CB_ERROR; + } + re_blocksize += cb.char_lists_size; } #endif +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 (re_blocksize > ccontext->max_pattern_compiled_length) @@ -10890,7 +10931,15 @@ if (re_blocksize > ccontext->max_pattern_compiled_length) goto HAD_CB_ERROR; } +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/vendor/pcre2/src/pcre2_compile_class.c b/vendor/pcre2/src/pcre2_compile_class.c index c6f30d6fc..c06066436 100644 --- a/vendor/pcre2/src/pcre2_compile_class.c +++ b/vendor/pcre2/src/pcre2_compile_class.c @@ -498,7 +498,7 @@ static const uint32_t char_list_starts[] = { static class_ranges * compile_optimize_class(uint32_t *start_ptr, uint32_t options, - uint32_t xoptions, compile_block *cb) + uint32_t xoptions, int *errorcodeptr, compile_block *cb) { class_ranges* cranges; uint32_t *ptr; @@ -538,12 +538,23 @@ PCRE2_ASSERT((range_list_size & 0x1) == 0); total_size = range_list_size + ((range_list_size >= 2) ? CHAR_LIST_EXTRA_SIZE : 0); +if (total_size > (PCRE2_SIZE_MAX - sizeof(class_ranges)) / sizeof(uint32_t)) + { + *errorcodeptr = ERR20; + cb->erroroffset = 0; + return NULL; + } cranges = cb->cx->memctl.malloc( sizeof(class_ranges) + total_size * sizeof(uint32_t), cb->cx->memctl.memory_data); -if (cranges == NULL) return NULL; +if (cranges == NULL) + { + *errorcodeptr = ERR21; + cb->erroroffset = 0; + return NULL; + } cranges->header.next = NULL; #ifdef PCRE2_DEBUG @@ -1120,13 +1131,10 @@ if (utf) { if (lengthptr != NULL) { - cranges = compile_optimize_class(pptr, options, xoptions, cb); + cranges = compile_optimize_class(pptr, options, xoptions, errorcodeptr, cb); if (cranges == NULL) - { - *errorcodeptr = ERR21; return NULL; - } /* Caching the pre-processed character ranges. */ if (cb->last_data != NULL) @@ -1759,18 +1767,17 @@ if ((xclass_props & XCLASS_REQUIRED) != 0) *lengthptr += 1 + LINK_SIZE; #endif - cb->char_lists_size += char_lists_size; - - char_lists_size /= sizeof(PCRE2_UCHAR); + PCRE2_ASSERT(BYTES2CU(cb->char_lists_size) <= MAX_PATTERN_SIZE); - /* Storage space for character lists is included - in the maximum pattern size. */ - if (*lengthptr > MAX_PATTERN_SIZE || - MAX_PATTERN_SIZE - *lengthptr < char_lists_size) + if (char_lists_size > PCRE2_SIZE_MAX - cb->char_lists_size || + BYTES2CU(char_lists_size) > MAX_PATTERN_SIZE || + BYTES2CU(cb->char_lists_size) > MAX_PATTERN_SIZE - BYTES2CU(char_lists_size)) { *errorcodeptr = ERR20; /* Pattern is too large */ return NULL; } + + cb->char_lists_size += char_lists_size; } else { @@ -1793,6 +1800,8 @@ if ((xclass_props & XCLASS_REQUIRED) != 0) Each list is aligned to 32 bit with an optional unused 16 bit value at the beginning of the character list. */ + PCRE2_ASSERT(char_lists_size <= PCRE2_SIZE_MAX - cb->char_lists_size); + cb->char_lists_size += char_lists_size; data = (uint8_t*)cb->start_code - cb->char_lists_size; diff --git a/vendor/pcre2/src/pcre2_dfa_match.c b/vendor/pcre2/src/pcre2_dfa_match.c index 314e97754..8e9512c4e 100644 --- a/vendor/pcre2/src/pcre2_dfa_match.c +++ b/vendor/pcre2/src/pcre2_dfa_match.c @@ -405,8 +405,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) @@ -422,9 +422,18 @@ more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb) { RWS_anchor *rws = *rwsptr; RWS_anchor *new; +uint32_t requested; + +PCRE2_ASSERT(ovecsize <= UINT32_MAX - RWS_RSIZE - RWS_ANCHOR_SIZE); +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; } @@ -434,14 +443,30 @@ overflow. */ else { - uint32_t newsize = (rws->size >= UINT32_MAX/(sizeof(int)*2))? UINT32_MAX/sizeof(int) : 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; @@ -2801,6 +2826,7 @@ for (;;) local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE); rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); @@ -2900,6 +2926,7 @@ for (;;) local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE); rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); @@ -2951,6 +2978,7 @@ for (;;) local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE; + PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_RSIZE); rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE; /* Check for repeating a recursion without advancing the subject @@ -3050,6 +3078,7 @@ for (;;) local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE); rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; if (codevalue == OP_BRAPOSZERO) @@ -3149,6 +3178,7 @@ for (;;) local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free); local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE; + PCRE2_ASSERT(rws->free >= RWS_RSIZE + RWS_OVEC_OSIZE); rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE; rc = internal_dfa_match( diff --git a/vendor/pcre2/src/pcre2_extuni.c b/vendor/pcre2/src/pcre2_extuni.c index 1b7f04b4b..fea098a76 100644 --- a/vendor/pcre2/src/pcre2_extuni.c +++ b/vendor/pcre2/src/pcre2_extuni.c @@ -54,12 +54,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; @@ -80,7 +80,7 @@ same behaviour. 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, @@ -90,7 +90,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) { BOOL was_ep_ZWJ = FALSE; @@ -121,7 +121,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/vendor/pcre2/src/pcre2_match.c b/vendor/pcre2/src/pcre2_match.c index a5a8421f7..966576e19 100644 --- a/vendor/pcre2/src/pcre2_match.c +++ b/vendor/pcre2/src/pcre2_match.c @@ -2895,7 +2895,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *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(); @@ -3246,7 +3246,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *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(); @@ -4071,7 +4071,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *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(); @@ -4660,7 +4660,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *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(); @@ -6243,7 +6243,7 @@ fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode, { for (i = 0; i < Lmax; i++) { - if (Feptr == mb->start_subject) + if (Feptr <= mb->check_subject) { if (i < Lmin) RRETURN(MATCH_NOMATCH); Lmax = i;