From 97833d7311ffbb6d209931bc2e2b9b7be8a53c74 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Tue, 12 May 2026 19:06:37 -0400 Subject: [PATCH] Widen class_ranges::range_list_size from uint16_t to size_t range_list_size is computed in pcre2_compile_class.c as a size_t from parse_class(), but stored into the class_ranges struct as uint16_t. The truncation affects only the stored count: the underlying allocation uses the full size_t value, so no out-of-bounds write occurs. Downstream consumers walk fewer entries than were allocated and produce wrong match results when the count exceeds 65535. Reachable on 16- or 32-bit lib builds with LINK_SIZE >= 3, where MAX_PATTERN_SIZE grows enough for a single character class to produce more than 65535 sorted-range entries. Not reachable on the default 8-bit lib with LINK_SIZE = 2. Widen the field to size_t to match parse_class()'s return type and the neighbouring char_lists_size / char_lists_start fields. The adjacent char_lists_types field stays uint16_t (it holds flag bits, not a count). --- src/pcre2_compile_class.c | 6 +++--- src/pcre2_intmodedep.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pcre2_compile_class.c b/src/pcre2_compile_class.c index c6f30d6fc..73dc13784 100644 --- a/src/pcre2_compile_class.c +++ b/src/pcre2_compile_class.c @@ -549,7 +549,7 @@ cranges->header.next = NULL; #ifdef PCRE2_DEBUG cranges->header.type = CDATA_CRANGE; #endif -cranges->range_list_size = (uint16_t)range_list_size; +cranges->range_list_size = range_list_size; cranges->char_lists_types = 0; cranges->char_lists_size = 0; cranges->char_lists_start = 0; @@ -618,7 +618,7 @@ ptr = buffer; while (ptr < dst && ptr[1] < 0x100) ptr += 2; if (dst - ptr < (2 * (6 - 1))) { - cranges->range_list_size = (uint16_t)(dst + 2 - buffer); + cranges->range_list_size = (size_t)(dst + 2 - buffer); return cranges; } @@ -740,7 +740,7 @@ PCRE2_ASSERT((uint16_t*)dst <= next_char); cranges->char_lists_size = (size_t)((uint8_t*)(buffer + total_size) - (uint8_t*)next_char); cranges->char_lists_start = (size_t)((uint8_t*)next_char - (uint8_t*)buffer); -cranges->range_list_size = (uint16_t)(dst - buffer); +cranges->range_list_size = (size_t)(dst - buffer); return cranges; } diff --git a/src/pcre2_intmodedep.h b/src/pcre2_intmodedep.h index 269c418fe..04f3ff874 100644 --- a/src/pcre2_intmodedep.h +++ b/src/pcre2_intmodedep.h @@ -778,7 +778,7 @@ typedef struct class_ranges { compile_data header; /* Common header */ size_t char_lists_size; /* Total size of encoded char lists */ size_t char_lists_start; /* Start offset of encoded char lists */ - uint16_t range_list_size; /* Size of ranges array */ + size_t range_list_size; /* Size of ranges array */ uint16_t char_lists_types; /* The XCL_LIST header of char lists */ /* Followed by the list of ranges (start/end pairs) */ } class_ranges;