Coverage Report

Created: 2026-09-03 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libgit2/deps/pcre2/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
96.1k
{
61
96.1k
uint16_t hash;
62
63
96.1k
PCRE2_ASSERT(length > 0);
64
65
96.1k
hash = (uint16_t)((name[0] & 0x7f) | ((name[length - 1] & 0xff) << 7));
66
96.1k
PCRE2_ASSERT(hash <= NAMED_GROUP_HASH_MASK);
67
96.1k
return hash;
68
96.1k
}
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
9.85k
{
90
9.85k
uint16_t hash = PRIV(compile_get_hash_from_name)(name, length);
91
9.85k
named_group *ng;
92
9.85k
named_group *end = cb->named_groups + cb->names_found;
93
94
22.9k
for (ng = cb->named_groups; ng < end; ng++)
95
21.1k
  if (length == ng->length && hash == NAMED_GROUP_GET_HASH(ng) &&
96
8.61k
      PRIV(strncmp)(name, ng->name, length) == 0) return ng;
97
98
1.75k
return NULL;
99
9.85k
}
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
1.29k
{
122
1.29k
uint32_t i;
123
1.29k
PCRE2_SPTR name = ng->name;
124
1.29k
int length = ng->length;
125
1.29k
uint32_t duplicate_count = 1;
126
127
1.29k
PCRE2_UCHAR *slot = cb->name_table;
128
129
1.29k
PCRE2_ASSERT(length > 0);
130
131
1.29k
if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0)
132
574
  {
133
574
  named_group *ng_it;
134
574
  named_group *end = cb->named_groups + cb->names_found;
135
136
26.1k
  for (ng_it = ng + 1; ng_it < end; ng_it++)
137
25.6k
    if (ng_it->name == name) duplicate_count++;
138
574
  }
139
140
16.9k
for (i = 0; i < tablecount; i++)
141
16.1k
  {
142
16.1k
  int crc = memcmp(name, slot + IMM2_SIZE, CU2BYTES(length));
143
16.1k
  if (crc == 0 && slot[IMM2_SIZE + length] != 0)
144
95
    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
16.1k
  if (crc < 0)
152
495
    {
153
495
    (void)memmove(slot + cb->name_entry_size * duplicate_count, slot,
154
495
      CU2BYTES((tablecount - i) * cb->name_entry_size));
155
495
    break;
156
495
    }
157
158
  /* Continue the loop for a later or duplicate name */
159
160
15.6k
  slot += cb->name_entry_size;
161
15.6k
  }
162
163
1.29k
tablecount += duplicate_count;
164
165
15.4k
while (TRUE)
166
15.4k
  {
167
15.4k
  PUT2(slot, 0, ng->number);
168
15.4k
  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
15.4k
  memset(slot + IMM2_SIZE + length, 0,
175
15.4k
    CU2BYTES(cb->name_entry_size - length - IMM2_SIZE));
176
177
15.4k
  if (--duplicate_count == 0) break;
178
179
22.7k
  while (TRUE)
180
22.7k
    {
181
22.7k
    ++ng;
182
22.7k
    if (ng->name == name) break;
183
22.7k
    }
184
185
14.1k
  slot += cb->name_entry_size;
186
14.1k
  }
187
188
1.29k
return tablecount;
189
1.29k
}
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
2.43k
{
215
2.43k
uint32_t i, groupnumber;
216
2.43k
int count;
217
2.43k
PCRE2_UCHAR *slot = cb->name_table;
218
219
/* Find the first entry in the table */
220
221
15.2k
for (i = 0; i < cb->names_found; i++)
222
15.2k
  {
223
15.2k
  if (PRIV(strncmp)(name, slot + IMM2_SIZE, length) == 0 &&
224
2.43k
      slot[IMM2_SIZE + length] == 0) break;
225
12.8k
  slot += cb->name_entry_size;
226
12.8k
  }
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
2.43k
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
2.43k
*indexptr = i;
245
2.43k
count = 0;
246
247
2.43k
for (;;)
248
95.3k
  {
249
95.3k
  count++;
250
95.3k
  groupnumber = GET2(slot, 0);
251
95.3k
  cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
252
95.3k
  if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
253
95.3k
  if (++i >= cb->names_found) break;
254
93.7k
  slot += cb->name_entry_size;
255
93.7k
  if (PRIV(strncmp)(name, slot + IMM2_SIZE, length) != 0 ||
256
93.4k
    (slot + IMM2_SIZE)[length] != 0) break;
257
93.7k
  }
258
259
2.43k
*countptr = count;
260
2.43k
return TRUE;
261
2.43k
}
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
3.04k
{
272
3.04k
size_t i, size = 0;
273
3.04k
named_group *ng;
274
3.04k
PCRE2_SPTR name;
275
3.04k
uint32_t length;
276
3.04k
named_group *end = cb->named_groups + cb->names_found;
277
278
23.2k
while (TRUE)
279
23.2k
  {
280
23.2k
  ++pptr;
281
282
23.2k
  switch (META_CODE(*pptr))
283
23.2k
    {
284
1.00k
    case META_OFFSET:
285
1.00k
    GETPLUSOFFSET(offset, pptr);
286
1.00k
    continue;
287
288
1.77k
    case META_CAPTURE_NAME:
289
1.77k
    offset += META_DATA(*pptr);
290
1.77k
    length = *(++pptr);
291
1.77k
    name = cb->start_pattern + offset;
292
293
1.77k
    ng = PRIV(compile_find_named_group)(name, length, cb);
294
295
1.77k
    if (ng == NULL)
296
23
      {
297
23
      *errorcodeptr = ERR15;
298
23
      cb->erroroffset = offset;
299
23
      return 0;
300
23
      }
301
302
1.75k
    if ((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) == 0)
303
339
      {
304
339
      pptr[-1] = META_CAPTURE_NUMBER;
305
339
      pptr[0] = ng->number;
306
339
      size++;
307
339
      continue;
308
339
      }
309
310
    /* Remains only for duplicated names. */
311
1.41k
    pptr[-1] = META_CAPTURE_NAME;
312
1.41k
    pptr[0] = (uint32_t)(ng - cb->named_groups);
313
1.41k
    size++;
314
1.41k
    name = ng->name;
315
316
129k
    while (++ng < end)
317
127k
      if (ng->name == name) size++;
318
1.41k
    continue;
319
320
17.4k
    case META_CAPTURE_NUMBER:
321
17.4k
    offset += META_DATA(*pptr);
322
323
17.4k
    i = *(++pptr);
324
17.4k
    if (i > cb->bracount)
325
33
      {
326
33
      *errorcodeptr = ERR15;
327
33
      cb->erroroffset = offset;
328
33
      return 0;
329
33
      }
330
17.4k
    if (i > cb->top_backref) cb->top_backref = (uint16_t)i;
331
17.4k
    size++;
332
17.4k
    continue;
333
334
2.99k
    default:
335
2.99k
    break;
336
23.2k
    }
337
338
2.99k
  PCRE2_ASSERT(size > 0);
339
2.99k
  return size;
340
23.2k
  }
341
3.04k
}
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
1.00k
{
365
1.00k
uint8_t *captures;
366
1.00k
uint8_t *capture_ptr;
367
1.00k
uint8_t bit;
368
1.00k
PCRE2_SPTR name;
369
1.00k
named_group *ng;
370
1.00k
named_group *end = cb->named_groups + cb->names_found;
371
1.00k
BOOL all_found;
372
1.00k
size_t size;
373
374
1.00k
PCRE2_ASSERT(*pptr == META_OFFSET);
375
1.00k
if (PRIV(compile_process_capture_list)(pptr - 1, 0, errorcodeptr, cb) == 0)
376
26
  return NULL;
377
378
/* Align to bytes. Since the highest capture can
379
be equal to bracount, +1 is added before the aligning. */
380
974
size = (cb->bracount + 1 + 7) >> 3;
381
974
captures = (uint8_t*)cb->cx->memctl.malloc(size, cb->cx->memctl.memory_data);
382
974
if (captures == NULL)
383
0
  {
384
0
  *errorcodeptr = ERR21;
385
0
  READPLUSOFFSET(cb->erroroffset, pptr);
386
0
  return NULL;
387
0
  }
388
389
974
memset(captures, 0, size);
390
391
3.33k
while (TRUE)
392
3.33k
  {
393
3.33k
  switch (META_CODE(*pptr))
394
3.33k
    {
395
974
    case META_OFFSET:
396
974
    pptr++;
397
974
    SKIPOFFSET(pptr);
398
974
    continue;
399
400
619
    case META_CAPTURE_NAME:
401
619
    ng = cb->named_groups + pptr[1];
402
619
    PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0);
403
619
    pptr += 2;
404
619
    name = ng->name;
405
406
619
    all_found = TRUE;
407
619
    do
408
7.30k
      {
409
7.30k
      if (ng->name != name) continue;
410
411
3.50k
      capture_ptr = captures + (ng->number >> 3);
412
3.50k
      PCRE2_ASSERT(capture_ptr < captures + size);
413
3.50k
      bit = (uint8_t)(1 << (ng->number & 0x7));
414
415
3.50k
      if ((*capture_ptr & bit) == 0)
416
2.59k
        {
417
2.59k
        *capture_ptr |= bit;
418
2.59k
        all_found = FALSE;
419
2.59k
        }
420
3.50k
      }
421
7.30k
    while (++ng < end);
422
423
619
    if (!all_found)
424
476
      {
425
476
      *lengthptr += 1 + 2 * IMM2_SIZE;
426
476
      continue;
427
476
      }
428
429
143
    pptr[-2] = META_CAPTURE_NUMBER;
430
143
    pptr[-1] = 0;
431
143
    continue;
432
433
764
    case META_CAPTURE_NUMBER:
434
764
    pptr += 2;
435
436
764
    capture_ptr = captures + (pptr[-1] >> 3);
437
764
    PCRE2_ASSERT(capture_ptr < captures + size);
438
764
    bit = (uint8_t)(1 << (pptr[-1] & 0x7));
439
440
764
    if ((*capture_ptr & bit) != 0)
441
132
      {
442
132
      pptr[-1] = 0;
443
132
      continue;
444
132
      }
445
446
632
    *capture_ptr |= bit;
447
632
    *lengthptr += 1 + IMM2_SIZE;
448
632
    continue;
449
450
974
    default:
451
974
    break;
452
3.33k
    }
453
454
974
  break;
455
3.33k
  }
456
457
974
cb->cx->memctl.free(captures, cb->cx->memctl.memory_data);
458
974
return pptr - 1;
459
974
}
460
461
462
/* Implement heapsort heapify algorithm. */
463
464
static void do_heapify_u16(uint16_t *captures, size_t size, size_t i)
465
181k
{
466
181k
size_t max;
467
181k
size_t left;
468
181k
size_t right;
469
181k
uint16_t tmp;
470
471
1.27M
while (TRUE)
472
1.27M
  {
473
1.27M
  max = i;
474
1.27M
  left = (i << 1) + 1;
475
1.27M
  right = left + 1;
476
477
1.27M
  if (left < size && captures[left] > captures[max]) max = left;
478
1.27M
  if (right < size && captures[right] > captures[max]) max = right;
479
1.27M
  if (i == max) return;
480
481
1.09M
  tmp = captures[i];
482
1.09M
  captures[i] = captures[max];
483
1.09M
  captures[max] = tmp;
484
1.09M
  i = max;
485
1.09M
  }
486
181k
}
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
2.04k
{
510
2.04k
uint32_t *pptr = pptr_start;
511
2.04k
size_t i, size;
512
2.04k
PCRE2_SPTR name;
513
2.04k
named_group *ng;
514
2.04k
named_group *end = cb->named_groups + cb->names_found;
515
2.04k
recurse_arguments *args;
516
2.04k
uint16_t *captures;
517
2.04k
uint16_t *current;
518
2.04k
uint16_t *captures_end;
519
2.04k
uint16_t tmp;
520
521
/* Process all arguments, compute the required size. */
522
523
2.04k
size = PRIV(compile_process_capture_list)(pptr, offset, errorcodeptr, cb);
524
2.04k
if (size == 0) return FALSE;
525
526
2.01k
args = cb->cx->memctl.malloc(
527
2.01k
  sizeof(recurse_arguments) + size * sizeof(uint16_t), cb->cx->memctl.memory_data);
528
529
2.01k
if (args == NULL)
530
0
  {
531
0
  *errorcodeptr = ERR21;
532
0
  cb->erroroffset = offset;
533
0
  return FALSE;
534
0
  }
535
536
2.01k
args->header.next = NULL;
537
#ifdef PCRE2_DEBUG
538
args->header.type = CDATA_RECURSE_ARGS;
539
#endif
540
2.01k
args->size = size;
541
542
/* Caching the pre-processed capture list. */
543
2.01k
if (cb->last_data != NULL)
544
1.83k
  cb->last_data->next = &args->header;
545
180
else
546
180
  cb->first_data = &args->header;
547
548
2.01k
cb->last_data = &args->header;
549
550
/* Create the capture list size. */
551
552
2.01k
captures = (uint16_t*)(args + 1);
553
554
19.7k
while (TRUE)
555
19.7k
  {
556
19.7k
  ++pptr;
557
558
19.7k
  switch (META_CODE(*pptr))
559
19.7k
    {
560
0
    case META_OFFSET:
561
0
    SKIPOFFSET(pptr);
562
0
    continue;
563
564
792
    case META_CAPTURE_NAME:
565
792
    ng = cb->named_groups + *(++pptr);
566
792
    PCRE2_ASSERT((ng->hash_dup & NAMED_GROUP_IS_DUPNAME) != 0);
567
792
    *captures++ = (uint16_t)(ng->number);
568
569
792
    name = ng->name;
570
571
122k
    while (++ng < end)
572
121k
      if (ng->name == name) *captures++ = (uint16_t)(ng->number);
573
792
    continue;
574
575
16.9k
    case META_CAPTURE_NUMBER:
576
16.9k
    *captures++ = *(++pptr);
577
16.9k
    continue;
578
579
2.01k
    default:
580
2.01k
    break;
581
19.7k
    }
582
583
2.01k
  break;
584
19.7k
  }
585
586
2.01k
PCRE2_ASSERT(size == (size_t)(captures - (uint16_t*)(args + 1)));
587
2.01k
args->skip_size = (size_t)(pptr - pptr_start) - 1;
588
589
2.01k
if (size == 1) return TRUE;
590
591
/* Sort captures. */
592
593
1.28k
captures = (uint16_t*)(args + 1);
594
1.28k
i = (size >> 1) - 1;
595
60.6k
while (TRUE)
596
60.6k
  {
597
60.6k
  do_heapify_u16(captures, size, i);
598
60.6k
  if (i == 0) break;
599
59.3k
  i--;
600
59.3k
  }
601
602
121k
for (i = size - 1; i > 0; i--)
603
120k
  {
604
120k
  tmp = captures[0];
605
120k
  captures[0] = captures[i];
606
120k
  captures[i] = tmp;
607
608
120k
  do_heapify_u16(captures, i, 0);
609
120k
  }
610
611
/* Remove duplicates. */
612
613
1.28k
captures_end = captures + size;
614
1.28k
tmp = *captures++;
615
1.28k
current = captures;
616
617
121k
while (current < captures_end)
618
120k
  {
619
120k
  if (*current != tmp)
620
105k
    {
621
105k
    tmp = *current;
622
105k
    *captures++ = tmp;
623
105k
    }
624
625
120k
  current++;
626
120k
  }
627
628
1.28k
args->size = (size_t)(captures - (uint16_t*)(args + 1));
629
1.28k
return TRUE;
630
2.01k
}
631
632
/* End of pcre2_compile_cgroup.c */