Coverage Report

Created: 2026-10-28 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poco/dependencies/pcre2/src/pcre2_compile_cgroup.c
Line
Count
Source
1
/*************************************************
2
*      Perl-Compatible Regular Expressions       *
3
*************************************************/
4
5
/* PCRE is a library of functions to support regular expressions whose syntax
6
and semantics are as close as possible to those of the Perl 5 language.
7
8
                       Written by Philip Hazel
9
     Original API code Copyright (c) 1997-2012 University of Cambridge
10
          New API code Copyright (c) 2016-2024 University of Cambridge
11
12
-----------------------------------------------------------------------------
13
Redistribution and use in source and binary forms, with or without
14
modification, are permitted provided that the following conditions are met:
15
16
    * Redistributions of source code must retain the above copyright notice,
17
      this list of conditions and the following disclaimer.
18
19
    * Redistributions in binary form must reproduce the above copyright
20
      notice, this list of conditions and the following disclaimer in the
21
      documentation and/or other materials provided with the distribution.
22
23
    * Neither the name of the University of Cambridge nor the names of its
24
      contributors may be used to endorse or promote products derived from
25
      this software without specific prior written permission.
26
27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
POSSIBILITY OF SUCH DAMAGE.
38
-----------------------------------------------------------------------------
39
*/
40
41
42
#include "pcre2_compile.h"
43
44
/*************************************************
45
*   Compute the hash code from a capture name    *
46
*************************************************/
47
48
/* This function returns with a simple hash code
49
computed from the name of a capture group.
50
51
Arguments:
52
  name         name of the capture group
53
  length       the length of the name
54
55
Returns:       hash code
56
*/
57
58
uint16_t
59
PRIV(compile_get_hash_from_name)(PCRE2_SPTR name, uint32_t length)
60
0
{
61
0
uint16_t hash;
62
63
0
PCRE2_ASSERT(length > 0);
64
65
0
hash = (uint16_t)((name[0] & 0x7f) | ((name[length - 1] & 0xff) << 7));
66
0
PCRE2_ASSERT(hash <= NAMED_GROUP_HASH_MASK);
67
0
return hash;
68
0
}
69
70
71
/*************************************************
72
*   Get the descriptor of a known named capture  *
73
*************************************************/
74
75
/* This function returns the descriptor in the
76
named group list of a known capture group.
77
78
Arguments:
79
  name         name of the capture group
80
  length       the length of the name
81
82
Returns:       pointer to the descriptor when found,
83
               NULL otherwise
84
 */
85
86
named_group *
87
PRIV(compile_find_named_group)(PCRE2_SPTR name,
88
  uint32_t length, compile_block *cb)
89
0
{
90
0
uint16_t hash = PRIV(compile_get_hash_from_name)(name, length);
91
0
named_group *ng;
92
0
named_group *end = cb->named_groups + cb->names_found;
93
94
0
for (ng = cb->named_groups; ng < end; ng++)
95
0
  if (length == ng->length && hash == NAMED_GROUP_GET_HASH(ng) &&
96
0
      PRIV(strncmp)(name, ng->name, length) == 0) return ng;
97
98
0
return NULL;
99
0
}
100
101
102
/*************************************************
103
*     Add an entry to the name/number table      *
104
*************************************************/
105
106
/* This function is called between compiling passes to add an entry to the
107
name/number table, maintaining alphabetical order. Checking for permitted
108
and forbidden duplicates has already been done.
109
110
Arguments:
111
  cb           the compile data block
112
  nb           named group entry
113
  tablecount   the count of names in the table so far
114
115
Returns:       new tablecount
116
*/
117
118
uint32_t
119
PRIV(compile_add_name_to_table)(compile_block *cb,
120
  named_group *ng, uint32_t tablecount)
121
0
{
122
0
uint32_t i;
123
0
PCRE2_SPTR name = ng->name;
124
0
int length = ng->length;
125
0
uint32_t duplicate_count = 1;
126
127
0
PCRE2_UCHAR *slot = cb->name_table;
128
129
0
PCRE2_ASSERT(length > 0);
130
131
0
if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0)
132
0
  {
133
0
  named_group *ng_it;
134
0
  named_group *end = cb->named_groups + cb->names_found;
135
136
0
  for (ng_it = ng + 1; ng_it < end; ng_it++)
137
0
    if (ng_it->name == name) duplicate_count++;
138
0
  }
139
140
0
for (i = 0; i < tablecount; i++)
141
0
  {
142
0
  int crc = memcmp(name, slot + IMM2_SIZE, CU2BYTES(length));
143
0
  if (crc == 0 && slot[IMM2_SIZE + length] != 0)
144
0
    crc = -1; /* Current name is a substring */
145
146
  /* Make space in the table and break the loop for an earlier name. For a
147
  duplicate or later name, carry on. We do this for duplicates so that in the
148
  simple case (when ?(| is not used) they are in order of their numbers. In all
149
  cases they are in the order in which they appear in the pattern. */
150
151
0
  if (crc < 0)
152
0
    {
153
0
    (void)memmove(slot + cb->name_entry_size * duplicate_count, slot,
154
0
      CU2BYTES((tablecount - i) * cb->name_entry_size));
155
0
    break;
156
0
    }
157
158
  /* Continue the loop for a later or duplicate name */
159
160
0
  slot += cb->name_entry_size;
161
0
  }
162
163
0
tablecount += duplicate_count;
164
165
0
while (TRUE)
166
0
  {
167
0
  PUT2(slot, 0, ng->number);
168
0
  memcpy(slot + IMM2_SIZE, name, CU2BYTES(length));
169
170
  /* Add a terminating zero and fill the rest of the slot with zeroes so that
171
  the memory is all initialized. Otherwise valgrind moans about uninitialized
172
  memory when saving serialized compiled patterns. */
173
174
0
  memset(slot + IMM2_SIZE + length, 0,
175
0
    CU2BYTES(cb->name_entry_size - length - IMM2_SIZE));
176
177
0
  if (--duplicate_count == 0) break;
178
179
0
  while (TRUE)
180
0
    {
181
0
    ++ng;
182
0
    if (ng->name == name) break;
183
0
    }
184
185
0
  slot += cb->name_entry_size;
186
0
  }
187
188
0
return tablecount;
189
0
}
190
191
192
/*************************************************
193
*    Find details of duplicate group names       *
194
*************************************************/
195
196
/* This is called from compile_branch() when it needs to know the index and
197
count of duplicates in the names table when processing named backreferences,
198
either directly, or as conditions.
199
200
Arguments:
201
  name          points to the name
202
  length        the length of the name
203
  indexptr      where to put the index
204
  countptr      where to put the count of duplicates
205
  errorcodeptr  where to put an error code
206
  cb            the compile block
207
208
Returns:        TRUE if OK, FALSE if not, error code set
209
*/
210
211
BOOL
212
PRIV(compile_find_dupname_details)(PCRE2_SPTR name, uint32_t length,
213
  int *indexptr, int *countptr, int *errorcodeptr, compile_block *cb)
214
0
{
215
0
uint32_t i, groupnumber;
216
0
int count;
217
0
PCRE2_UCHAR *slot = cb->name_table;
218
219
/* Find the first entry in the table */
220
221
0
for (i = 0; i < cb->names_found; i++)
222
0
  {
223
0
  if (PRIV(strncmp)(name, slot + IMM2_SIZE, length) == 0 &&
224
0
      slot[IMM2_SIZE + length] == 0) break;
225
0
  slot += cb->name_entry_size;
226
0
  }
227
228
/* This should not occur, because this function is called only when we know we
229
have duplicate names. Give an internal error. */
230
231
/* LCOV_EXCL_START */
232
0
if (i >= cb->names_found)
233
0
  {
234
0
  PCRE2_DEBUG_UNREACHABLE();
235
0
  *errorcodeptr = ERR53;
236
0
  cb->erroroffset = name - cb->start_pattern;
237
0
  return FALSE;
238
0
  }
239
/* LCOV_EXCL_STOP */
240
241
/* Record the index and then see how many duplicates there are, updating the
242
backref map and maximum back reference as we do. */
243
244
0
*indexptr = i;
245
0
count = 0;
246
247
0
for (;;)
248
0
  {
249
0
  count++;
250
0
  groupnumber = GET2(slot, 0);
251
0
  cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
252
0
  if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
253
0
  if (++i >= cb->names_found) break;
254
0
  slot += cb->name_entry_size;
255
0
  if (PRIV(strncmp)(name, slot + IMM2_SIZE, length) != 0 ||
256
0
    (slot + IMM2_SIZE)[length] != 0) break;
257
0
  }
258
259
0
*countptr = count;
260
0
return TRUE;
261
0
}
262
263
264
/* Process the capture list of scan substring and recurse
265
operations. Since at least one argument must be present,
266
a 0 return value represents error. */
267
268
static size_t
269
PRIV(compile_process_capture_list)(uint32_t *pptr, PCRE2_SIZE offset,
270
  int *errorcodeptr, compile_block *cb)
271
0
{
272
0
size_t i, size = 0;
273
0
named_group *ng;
274
0
PCRE2_SPTR name;
275
0
uint32_t length;
276
0
named_group *end = cb->named_groups + cb->names_found;
277
278
0
while (TRUE)
279
0
  {
280
0
  ++pptr;
281
282
0
  switch (META_CODE(*pptr))
283
0
    {
284
0
    case META_OFFSET:
285
0
    GETPLUSOFFSET(offset, pptr);
286
0
    continue;
287
288
0
    case META_CAPTURE_NAME:
289
0
    offset += META_DATA(*pptr);
290
0
    length = *(++pptr);
291
0
    name = cb->start_pattern + offset;
292
293
0
    ng = PRIV(compile_find_named_group)(name, length, cb);
294
295
0
    if (ng == NULL)
296
0
      {
297
0
      *errorcodeptr = ERR15;
298
0
      cb->erroroffset = offset;
299
0
      return 0;
300
0
      }
301
302
0
    if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) == 0)
303
0
      {
304
0
      pptr[-1] = META_CAPTURE_NUMBER;
305
0
      pptr[0] = ng->number;
306
0
      size++;
307
0
      continue;
308
0
      }
309
310
    /* Remains only for duplicated names. */
311
0
    pptr[-1] = META_CAPTURE_NAME;
312
0
    pptr[0] = (uint32_t)(ng - cb->named_groups);
313
0
    size++;
314
0
    name = ng->name;
315
316
0
    while (++ng < end)
317
0
      if (ng->name == name) size++;
318
0
    continue;
319
320
0
    case META_CAPTURE_NUMBER:
321
0
    offset += META_DATA(*pptr);
322
323
0
    i = *(++pptr);
324
0
    if (i > cb->bracount)
325
0
      {
326
0
      *errorcodeptr = ERR15;
327
0
      cb->erroroffset = offset;
328
0
      return 0;
329
0
      }
330
0
    if (i > cb->top_backref) cb->top_backref = (uint16_t)i;
331
0
    size++;
332
0
    continue;
333
334
0
    default:
335
0
    break;
336
0
    }
337
338
0
  PCRE2_ASSERT(size > 0);
339
0
  return size;
340
0
  }
341
0
}
342
343
344
/*******************************************************
345
*   Parse the arguments of scan substring operations   *
346
********************************************************/
347
348
/* This function parses the arguments of scan substring operations.
349
350
Arguments:
351
  pptr_start    points to the current parsed pattern pointer
352
  offset        argument starting offset in the pattern
353
  errorcodeptr  where to put an error code
354
  cb            the compile block
355
  lengthptr     NULL during the real compile phase
356
                points to length accumulator during pre-compile phase
357
358
Returns:        TRUE if OK, FALSE if not, error code set
359
*/
360
361
uint32_t *
362
PRIV(compile_parse_scan_substr_args)(uint32_t *pptr,
363
  int *errorcodeptr, compile_block *cb, PCRE2_SIZE *lengthptr)
364
0
{
365
0
uint8_t *captures;
366
0
uint8_t *capture_ptr;
367
0
uint8_t bit;
368
0
PCRE2_SPTR name;
369
0
named_group *ng;
370
0
named_group *end = cb->named_groups + cb->names_found;
371
0
BOOL all_found;
372
0
size_t size;
373
374
0
PCRE2_ASSERT(*pptr == META_OFFSET);
375
0
if (PRIV(compile_process_capture_list)(pptr - 1, 0, errorcodeptr, cb) == 0)
376
0
  return NULL;
377
378
/* Align to bytes. Since the highest capture can
379
be equal to bracount, +1 is added before the aligning. */
380
0
size = (cb->bracount + 1 + 7) >> 3;
381
0
captures = (uint8_t*)cb->cx->memctl.malloc(size, cb->cx->memctl.memory_data);
382
0
if (captures == NULL)
383
0
  {
384
0
  *errorcodeptr = ERR21;
385
0
  READPLUSOFFSET(cb->erroroffset, pptr);
386
0
  return NULL;
387
0
  }
388
389
0
memset(captures, 0, size);
390
391
0
while (TRUE)
392
0
  {
393
0
  switch (META_CODE(*pptr))
394
0
    {
395
0
    case META_OFFSET:
396
0
    pptr++;
397
0
    SKIPOFFSET(pptr);
398
0
    continue;
399
400
0
    case META_CAPTURE_NAME:
401
0
    ng = cb->named_groups + pptr[1];
402
0
    PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0);
403
0
    pptr += 2;
404
0
    name = ng->name;
405
406
0
    all_found = TRUE;
407
0
    do
408
0
      {
409
0
      if (ng->name != name) continue;
410
411
0
      capture_ptr = captures + (ng->number >> 3);
412
0
      PCRE2_ASSERT(capture_ptr < captures + size);
413
0
      bit = (uint8_t)(1 << (ng->number & 0x7));
414
415
0
      if ((*capture_ptr & bit) == 0)
416
0
        {
417
0
        *capture_ptr |= bit;
418
0
        all_found = FALSE;
419
0
        }
420
0
      }
421
0
    while (++ng < end);
422
423
0
    if (!all_found)
424
0
      {
425
0
      *lengthptr += 1 + 2 * IMM2_SIZE;
426
0
      continue;
427
0
      }
428
429
0
    pptr[-2] = META_CAPTURE_NUMBER;
430
0
    pptr[-1] = 0;
431
0
    continue;
432
433
0
    case META_CAPTURE_NUMBER:
434
0
    pptr += 2;
435
436
0
    capture_ptr = captures + (pptr[-1] >> 3);
437
0
    PCRE2_ASSERT(capture_ptr < captures + size);
438
0
    bit = (uint8_t)(1 << (pptr[-1] & 0x7));
439
440
0
    if ((*capture_ptr & bit) != 0)
441
0
      {
442
0
      pptr[-1] = 0;
443
0
      continue;
444
0
      }
445
446
0
    *capture_ptr |= bit;
447
0
    *lengthptr += 1 + IMM2_SIZE;
448
0
    continue;
449
450
0
    default:
451
0
    break;
452
0
    }
453
454
0
  break;
455
0
  }
456
457
0
cb->cx->memctl.free(captures, cb->cx->memctl.memory_data);
458
0
return pptr - 1;
459
0
}
460
461
462
/* Implement heapsort heapify algorithm. */
463
464
static void do_heapify_u16(uint16_t *captures, size_t size, size_t i)
465
0
{
466
0
size_t max;
467
0
size_t left;
468
0
size_t right;
469
0
uint16_t tmp;
470
471
0
while (TRUE)
472
0
  {
473
0
  max = i;
474
0
  left = (i << 1) + 1;
475
0
  right = left + 1;
476
477
0
  if (left < size && captures[left] > captures[max]) max = left;
478
0
  if (right < size && captures[right] > captures[max]) max = right;
479
0
  if (i == max) return;
480
481
0
  tmp = captures[i];
482
0
  captures[i] = captures[max];
483
0
  captures[max] = tmp;
484
0
  i = max;
485
0
  }
486
0
}
487
488
489
/*************************************************
490
*   Parse the arguments of recurse operations    *
491
*************************************************/
492
493
/* This function parses the arguments of recurse operations.
494
495
Arguments:
496
  pptr_start    the current parsed pattern pointer
497
  offset        argument starting offset in the pattern
498
  errorcodeptr  where to put an error code
499
  cb            the compile block
500
  lengthptr     NULL during the real compile phase
501
                points to length accumulator during pre-compile phase
502
503
Returns:        TRUE if OK, FALSE if not, error code set
504
*/
505
506
BOOL
507
PRIV(compile_parse_recurse_args)(uint32_t *pptr_start,
508
  PCRE2_SIZE offset, int *errorcodeptr, compile_block *cb)
509
0
{
510
0
uint32_t *pptr = pptr_start;
511
0
size_t i, size;
512
0
PCRE2_SPTR name;
513
0
named_group *ng;
514
0
named_group *end = cb->named_groups + cb->names_found;
515
0
recurse_arguments *args;
516
0
uint16_t *captures;
517
0
uint16_t *current;
518
0
uint16_t *captures_end;
519
0
uint16_t tmp;
520
521
/* Process all arguments, compute the required size. */
522
523
0
size = PRIV(compile_process_capture_list)(pptr, offset, errorcodeptr, cb);
524
0
if (size == 0) return FALSE;
525
526
0
args = cb->cx->memctl.malloc(
527
0
  sizeof(recurse_arguments) + size * sizeof(uint16_t), cb->cx->memctl.memory_data);
528
529
0
if (args == NULL)
530
0
  {
531
0
  *errorcodeptr = ERR21;
532
0
  cb->erroroffset = offset;
533
0
  return FALSE;
534
0
  }
535
536
0
args->header.next = NULL;
537
#ifdef PCRE2_DEBUG
538
args->header.type = CDATA_RECURSE_ARGS;
539
#endif
540
0
args->size = size;
541
542
/* Caching the pre-processed capture list. */
543
0
if (cb->last_data != NULL)
544
0
  cb->last_data->next = &args->header;
545
0
else
546
0
  cb->first_data = &args->header;
547
548
0
cb->last_data = &args->header;
549
550
/* Create the capture list size. */
551
552
0
captures = (uint16_t*)(args + 1);
553
554
0
while (TRUE)
555
0
  {
556
0
  ++pptr;
557
558
0
  switch (META_CODE(*pptr))
559
0
    {
560
0
    case META_OFFSET:
561
0
    SKIPOFFSET(pptr);
562
0
    continue;
563
564
0
    case META_CAPTURE_NAME:
565
0
    ng = cb->named_groups + *(++pptr);
566
0
    PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0);
567
0
    *captures++ = (uint16_t)(ng->number);
568
569
0
    name = ng->name;
570
571
0
    while (++ng < end)
572
0
      if (ng->name == name) *captures++ = (uint16_t)(ng->number);
573
0
    continue;
574
575
0
    case META_CAPTURE_NUMBER:
576
0
    *captures++ = *(++pptr);
577
0
    continue;
578
579
0
    default:
580
0
    break;
581
0
    }
582
583
0
  break;
584
0
  }
585
586
0
PCRE2_ASSERT(size == (size_t)(captures - (uint16_t*)(args + 1)));
587
0
args->skip_size = (size_t)(pptr - pptr_start) - 1;
588
589
0
if (size == 1) return TRUE;
590
591
/* Sort captures. */
592
593
0
captures = (uint16_t*)(args + 1);
594
0
i = (size >> 1) - 1;
595
0
while (TRUE)
596
0
  {
597
0
  do_heapify_u16(captures, size, i);
598
0
  if (i == 0) break;
599
0
  i--;
600
0
  }
601
602
0
for (i = size - 1; i > 0; i--)
603
0
  {
604
0
  tmp = captures[0];
605
0
  captures[0] = captures[i];
606
0
  captures[i] = tmp;
607
608
0
  do_heapify_u16(captures, i, 0);
609
0
  }
610
611
/* Remove duplicates. */
612
613
0
captures_end = captures + size;
614
0
tmp = *captures++;
615
0
current = captures;
616
617
0
while (current < captures_end)
618
0
  {
619
0
  if (*current != tmp)
620
0
    {
621
0
    tmp = *current;
622
0
    *captures++ = tmp;
623
0
    }
624
625
0
  current++;
626
0
  }
627
628
0
args->size = (size_t)(captures - (uint16_t*)(args + 1));
629
0
return TRUE;
630
0
}
631
632
/* End of pcre2_compile_cgroup.c */