Coverage Report

Created: 2025-07-11 06:40

/src/httpd/srclib/apr/strings/apr_strings.c
Line
Count
Source (jump to first uncovered line)
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
/*
17
 * Copyright (c) 1990, 1993
18
 *  The Regents of the University of California.  All rights reserved.
19
 *
20
 * Redistribution and use in source and binary forms, with or without
21
 * modification, are permitted provided that the following conditions
22
 * are met:
23
 * 1. Redistributions of source code must retain the above copyright
24
 *    notice, this list of conditions and the following disclaimer.
25
 * 2. Redistributions in binary form must reproduce the above copyright
26
 *    notice, this list of conditions and the following disclaimer in the
27
 *    documentation and/or other materials provided with the distribution.
28
 * 3. All advertising materials mentioning features or use of this software
29
 *    must display the following acknowledgement:
30
 *  This product includes software developed by the University of
31
 *  California, Berkeley and its contributors.
32
 * 4. Neither the name of the University nor the names of its contributors
33
 *    may be used to endorse or promote products derived from this software
34
 *    without specific prior written permission.
35
 *
36
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
37
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
40
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46
 * SUCH DAMAGE.
47
 */
48
49
#include "apr.h"
50
#include "apr_strings.h"
51
#include "apr_general.h"
52
#include "apr_private.h"
53
#include "apr_lib.h"
54
#define APR_WANT_STDIO
55
#define APR_WANT_STRFUNC
56
#include "apr_want.h"
57
58
#ifdef HAVE_STDDEF_H
59
#include <stddef.h> /* NULL */
60
#endif
61
#ifdef HAVE_LIMITS_H
62
#include <limits.h> /* INT_MAX */
63
#endif
64
65
#ifdef HAVE_STDLIB_H
66
#include <stdlib.h> /* strtol and strtoll */
67
#endif
68
69
/** this is used to cache lengths in apr_pstrcat */
70
7.74k
#define MAX_SAVED_LENGTHS  6
71
72
APR_DECLARE(char *) apr_pstrdup(apr_pool_t *a, const char *s)
73
54.4k
{
74
54.4k
    char *res;
75
54.4k
    apr_size_t len;
76
77
54.4k
    if (s == NULL) {
78
0
        return NULL;
79
0
    }
80
54.4k
    len = strlen(s) + 1;
81
54.4k
    res = apr_pmemdup(a, s, len);
82
54.4k
    return res;
83
54.4k
}
84
85
APR_DECLARE(char *) apr_pstrndup(apr_pool_t *a, const char *s, apr_size_t n)
86
209
{
87
209
    char *res;
88
209
    const char *end;
89
90
209
    if (s == NULL) {
91
0
        return NULL;
92
0
    }
93
209
    end = memchr(s, '\0', n);
94
209
    if (end != NULL)
95
0
        n = end - s;
96
209
    res = apr_palloc(a, n + 1);
97
209
    memcpy(res, s, n);
98
209
    res[n] = '\0';
99
209
    return res;
100
209
}
101
102
APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *a, const char *s, apr_size_t n)
103
6.34k
{
104
6.34k
    char *res;
105
106
6.34k
    if (s == NULL) {
107
0
        return NULL;
108
0
    }
109
6.34k
    res = apr_palloc(a, n + 1);
110
6.34k
    memcpy(res, s, n);
111
6.34k
    res[n] = '\0';
112
6.34k
    return res;
113
6.34k
}
114
115
APR_DECLARE(void *) apr_pmemdup(apr_pool_t *a, const void *m, apr_size_t n)
116
68.7k
{
117
68.7k
    void *res;
118
119
68.7k
    if (m == NULL)
120
0
  return NULL;
121
68.7k
    res = apr_palloc(a, n);
122
68.7k
    memcpy(res, m, n);
123
68.7k
    return res;
124
68.7k
}
125
126
APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *a, ...)
127
816
{
128
816
    char *cp, *argp, *res;
129
816
    apr_size_t saved_lengths[MAX_SAVED_LENGTHS];
130
816
    int nargs = 0;
131
132
    /* Pass one --- find length of required string */
133
134
816
    apr_size_t len = 0;
135
816
    va_list adummy;
136
137
816
    va_start(adummy, a);
138
139
4.68k
    while ((cp = va_arg(adummy, char *)) != NULL) {
140
3.87k
        apr_size_t cplen = strlen(cp);
141
3.87k
        if (nargs < MAX_SAVED_LENGTHS) {
142
3.72k
            saved_lengths[nargs++] = cplen;
143
3.72k
        }
144
3.87k
        len += cplen;
145
3.87k
    }
146
147
816
    va_end(adummy);
148
149
    /* Allocate the required string */
150
151
816
    res = (char *) apr_palloc(a, len + 1);
152
816
    cp = res;
153
154
    /* Pass two --- copy the argument strings into the result space */
155
156
816
    va_start(adummy, a);
157
158
816
    nargs = 0;
159
4.68k
    while ((argp = va_arg(adummy, char *)) != NULL) {
160
3.87k
        if (nargs < MAX_SAVED_LENGTHS) {
161
3.72k
            len = saved_lengths[nargs++];
162
3.72k
        }
163
150
        else {
164
150
            len = strlen(argp);
165
150
        }
166
167
3.87k
        memcpy(cp, argp, len);
168
3.87k
        cp += len;
169
3.87k
    }
170
171
816
    va_end(adummy);
172
173
    /* Return the result string */
174
175
816
    *cp = '\0';
176
177
816
    return res;
178
816
}
179
180
APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *a, const struct iovec *vec,
181
                                 apr_size_t nvec, apr_size_t *nbytes)
182
0
{
183
0
    apr_size_t i;
184
0
    apr_size_t len;
185
0
    const struct iovec *src;
186
0
    char *res;
187
0
    char *dst;
188
189
    /* Pass one --- find length of required string */
190
0
    len = 0;
191
0
    src = vec;
192
0
    for (i = nvec; i; i--) {
193
0
        len += src->iov_len;
194
0
        src++;
195
0
    }
196
0
    if (nbytes) {
197
0
        *nbytes = len;
198
0
    }
199
200
    /* Allocate the required string */
201
0
    res = (char *) apr_palloc(a, len + 1);
202
203
    /* Pass two --- copy the argument strings into the result space */
204
0
    src = vec;
205
0
    dst = res;
206
0
    for (i = nvec; i; i--) {
207
0
        memcpy(dst, src->iov_base, src->iov_len);
208
0
        dst += src->iov_len;
209
0
        src++;
210
0
    }
211
212
    /* Return the result string */
213
0
    *dst = '\0';
214
215
0
    return res;
216
0
}
217
218
#if defined(HAVE_WEAK_SYMBOLS)
219
void apr__memzero_explicit(void *buffer, apr_size_t size);
220
221
__attribute__ ((weak))
222
void apr__memzero_explicit(void *buffer, apr_size_t size)
223
0
{
224
0
    memset(buffer, 0, size);
225
0
}
226
#endif
227
228
APR_DECLARE(apr_status_t) apr_memzero_explicit(void *buffer, apr_size_t size)
229
0
{
230
#if defined(WIN32)
231
    SecureZeroMemory(buffer, size);
232
#elif defined(HAVE_EXPLICIT_BZERO)
233
    explicit_bzero(buffer, size);
234
#elif defined(HAVE_MEMSET_S)
235
    if (size) {
236
        return memset_s(buffer, (rsize_t)size, 0, (rsize_t)size);
237
    }
238
#elif defined(HAVE_WEAK_SYMBOLS)
239
    apr__memzero_explicit(buffer, size);
240
#else
241
    apr_size_t i;
242
    volatile unsigned char *volatile ptr = buffer;
243
    for (i = 0; i < size; ++i) {
244
        ptr[i] = 0;
245
    }
246
#endif
247
0
    return APR_SUCCESS;
248
0
}
249
250
/* A volatile variable which is always zero but allows to block the compiler
251
 * from optimizing or eliding code using it. Volatile forces the compiler to
252
 * emit a memory load for which no value can be assumed, so for instance an
253
 * add/sub/xor/or with "optblocker" is a noop that will hide the result to
254
 * the optimizer.
255
 */
256
static volatile const apr_uint32_t optblocker;
257
258
/* Return whether x is not zero, with no branching controlled by x.
259
 *
260
 * Taken from the cryptoint library (public domain) by D. J. Bernstein,
261
 * which provides timing attacks safe integer operations/primitives.
262
 * Code:
263
 *   https://lib.mceliece.org/libmceliece-20250507/cryptoint/crypto_uint32.h
264
 * Paper:
265
 *   https://cr.yp.to/papers/cryptoint-20250424.pdf
266
 */
267
#if __has_attribute(always_inline)
268
__attribute__((always_inline))
269
#endif
270
static APR_INLINE int test_nonzero_timingsafe(apr_uint32_t x)
271
0
{
272
0
    x |= -x; /* sets the most significant bit unless x == 0 */
273
274
    /* shift bit 31 (MSB) to bit 0 */
275
0
    x >>= 32-6;      /* keep 6 bits */
276
0
    x += optblocker; /* lose the optimizer */
277
0
    x >>= 5;         /* keep the (original) MSB only */
278
279
    /* x is now 0 or 1 */
280
0
    return x & INT_MAX;
281
0
}
282
283
APR_DECLARE(int) apr_memeq_timingsafe(const void *buf1, const void *buf2,
284
                                      apr_size_t n)
285
0
{
286
0
    apr_uint32_t diff = 0;
287
0
    volatile apr_size_t count = n; /* prevent loop unrolling */
288
0
    apr_size_t i = 0;
289
290
0
    for (; i < count; ++i) {
291
0
        const unsigned char c1 = ((volatile const unsigned char *)buf1)[i];
292
0
        const unsigned char c2 = ((volatile const unsigned char *)buf2)[i];
293
294
0
        diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */
295
0
    }
296
297
    /* (diff == 0) <=> (diff != 0) ^ 1 */
298
0
    return test_nonzero_timingsafe(diff) ^ 1;
299
0
}
300
301
APR_DECLARE(int) apr_streq_timingsafe(const char *sec1, const char *str2)
302
0
{
303
0
    apr_uint32_t diff = 0;
304
0
    apr_size_t i1 = 0, i2 = 0;
305
306
0
    for (;; ++i2) {
307
0
        const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1];
308
0
        const unsigned char c2 = ((volatile const unsigned char *)str2)[i2];
309
310
0
        diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */
311
312
        /* Not a shortest/longest match because an attacker would usually know
313
         * one of the strings and could then determine the length of the other.
314
         * So assume only sec1 and its length are secret and stop the loop at
315
         * the end of str2. If sec1 is shorter than str2 the loop will continue
316
         * by comparing the rest of str2 with the trailing NUL byte of sec1.
317
         * In any case since the diff above is computed up to and including a
318
         * NUL byte, only the same content and length will raise match.
319
         */
320
0
        if (!c2) {
321
0
            break;
322
0
        }
323
324
        /* Don't go above sec1's NUL byte */
325
0
        i1 += test_nonzero_timingsafe(c1);
326
0
    }
327
328
    /* (diff == 0) <=> (diff != 0) ^ 1 */
329
0
    return test_nonzero_timingsafe(diff) ^ 1;
330
0
}
331
332
APR_DECLARE(int) apr_strneq_timingsafe(const char *sec1, const char *str2,
333
                                       apr_size_t n)
334
0
{
335
0
    apr_uint32_t diff = 0;
336
0
    volatile apr_size_t count = n; /* prevent loop unrolling */
337
0
    apr_size_t i1 = 0, i2 = 0;
338
339
0
    for (; i2 < count; ++i2) {
340
0
        const unsigned char c1 = ((volatile const unsigned char *)sec1)[i1];
341
0
        const unsigned char c2 = ((volatile const unsigned char *)str2)[i2];
342
343
0
        diff |= c1 ^ c2; /* sets diff to non-zero whenever c1 != c2 */
344
345
        /* Not a shortest/longest match because an attacker would usually know
346
         * one of the strings and could then determine the length of the other.
347
         * So assume only sec1 and its length are secret and stop the loop at
348
         * the end of str2. If sec1 is shorter than str2 the loop will continue
349
         * by comparing the rest of str2 with the trailing NUL byte of sec1.
350
         * In any case since the diff above is computed up to and including a
351
         * NUL byte, only the same content and length will raise match.
352
         */
353
0
        if (!c2) {
354
0
            break;
355
0
        }
356
357
        /* Don't go above sec1's NUL byte */
358
0
        i1 += test_nonzero_timingsafe(c1);
359
0
    }
360
361
    /* (diff == 0) <=> (diff != 0) ^ 1 */
362
0
    return test_nonzero_timingsafe(diff) ^ 1;
363
0
}
364
365
#if (!APR_HAVE_MEMCHR)
366
void *memchr(const void *s, int c, size_t n)
367
{
368
    const char *cp;
369
370
    for (cp = s; n > 0; n--, cp++) {
371
        if (*cp == c)
372
            return (char *) cp; /* Casting away the const here */
373
    }
374
375
    return NULL;
376
}
377
#endif
378
379
#ifndef INT64_MAX
380
#define INT64_MAX  APR_INT64_C(0x7fffffffffffffff)
381
#endif
382
#ifndef INT64_MIN
383
#define INT64_MIN (-APR_INT64_C(0x7fffffffffffffff) - APR_INT64_C(1))
384
#endif
385
386
APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *nptr,
387
                                      char **endptr, int base)
388
0
{
389
0
    errno = 0;
390
0
    *offset = APR_OFF_T_STRFN(nptr, endptr, base);
391
0
    return APR_FROM_OS_ERROR(errno);
392
0
}
393
394
APR_DECLARE(apr_int64_t) apr_strtoi64(const char *nptr, char **endptr, int base)
395
1.25k
{
396
1.25k
#ifdef APR_INT64_STRFN
397
1.25k
    errno = 0;
398
1.25k
    return APR_INT64_STRFN(nptr, endptr, base);
399
#else
400
    const char *s;
401
    apr_int64_t acc;
402
    apr_int64_t val;
403
    int neg, any;
404
    char c;
405
406
    errno = 0;
407
    /*
408
     * Skip white space and pick up leading +/- sign if any.
409
     * If base is 0, allow 0x for hex and 0 for octal, else
410
     * assume decimal; if base is already 16, allow 0x.
411
     */
412
    s = nptr;
413
    do {
414
  c = *s++;
415
    } while (apr_isspace(c));
416
    if (c == '-') {
417
  neg = 1;
418
  c = *s++;
419
    } else {
420
  neg = 0;
421
  if (c == '+')
422
      c = *s++;
423
    }
424
    if ((base == 0 || base == 16) &&
425
  c == '0' && (*s == 'x' || *s == 'X')) {
426
      c = s[1];
427
      s += 2;
428
      base = 16;
429
    }
430
    if (base == 0)
431
  base = c == '0' ? 8 : 10;
432
    acc = any = 0;
433
    if (base < 2 || base > 36) {
434
  errno = EINVAL;
435
        if (endptr != NULL)
436
      *endptr = (char *)(any ? s - 1 : nptr);
437
        return acc;
438
    }
439
440
    /* The classic bsd implementation requires div/mod operators
441
     * to compute a cutoff.  Benchmarking proves that is very, very
442
     * evil to some 32 bit processors.  Instead, look for underflow
443
     * in both the mult and add/sub operation.  Unlike the bsd impl,
444
     * we also work strictly in a signed int64 word as we haven't
445
     * implemented the unsigned type in win32.
446
     *
447
     * Set 'any' if any `digits' consumed; make it negative to indicate
448
     * overflow.
449
     */
450
    val = 0;
451
    for ( ; ; c = *s++) {
452
        if (c >= '0' && c <= '9')
453
      c -= '0';
454
#if (('Z' - 'A') == 25)
455
  else if (c >= 'A' && c <= 'Z')
456
      c -= 'A' - 10;
457
  else if (c >= 'a' && c <= 'z')
458
      c -= 'a' - 10;
459
#elif APR_CHARSET_EBCDIC
460
  else if (c >= 'A' && c <= 'I')
461
      c -= 'A' - 10;
462
  else if (c >= 'J' && c <= 'R')
463
      c -= 'J' - 19;
464
  else if (c >= 'S' && c <= 'Z')
465
      c -= 'S' - 28;
466
  else if (c >= 'a' && c <= 'i')
467
      c -= 'a' - 10;
468
  else if (c >= 'j' && c <= 'r')
469
      c -= 'j' - 19;
470
  else if (c >= 's' && c <= 'z')
471
      c -= 'z' - 28;
472
#else
473
#error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported"
474
#endif
475
  else
476
      break;
477
  if (c >= base)
478
      break;
479
  val *= base;
480
        if ( (any < 0)  /* already noted an over/under flow - short circuit */
481
           || (neg && (val > acc || (val -= c) > acc)) /* underflow */
482
           || (!neg && (val < acc || (val += c) < acc))) {       /* overflow */
483
            any = -1; /* once noted, over/underflows never go away */
484
#ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR
485
            break;
486
#endif
487
        } else {
488
            acc = val;
489
      any = 1;
490
        }
491
    }
492
493
    if (any < 0) {
494
  acc = neg ? INT64_MIN : INT64_MAX;
495
  errno = ERANGE;
496
    } else if (!any) {
497
  errno = EINVAL;
498
    }
499
    if (endptr != NULL)
500
  *endptr = (char *)(any ? s - 1 : nptr);
501
    return (acc);
502
#endif
503
1.25k
}
504
505
APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf)
506
0
{
507
0
    return apr_strtoi64(buf, NULL, 10);
508
0
}
509
510
APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n)
511
0
{
512
0
    const int BUFFER_SIZE = sizeof(int) * 3 + 2;
513
0
    char *buf = apr_palloc(p, BUFFER_SIZE);
514
0
    char *start = buf + BUFFER_SIZE - 1;
515
0
    unsigned int un;
516
0
    int negative;
517
0
    if (n < 0) {
518
0
  negative = 1;
519
0
  un = -n;
520
0
    }
521
0
    else {
522
0
  negative = 0;
523
0
        un = n;
524
0
    }
525
0
    *start = 0;
526
0
    do {
527
0
  *--start = '0' + (un % 10);
528
0
  un /= 10;
529
0
    } while (un);
530
0
    if (negative) {
531
0
  *--start = '-';
532
0
    }
533
0
    return start;
534
0
}
535
536
APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n)
537
0
{
538
0
    const int BUFFER_SIZE = sizeof(long) * 3 + 2;
539
0
    char *buf = apr_palloc(p, BUFFER_SIZE);
540
0
    char *start = buf + BUFFER_SIZE - 1;
541
0
    int negative;
542
0
    unsigned int un;
543
0
    if (n < 0) {
544
0
  negative = 1;
545
0
  un = -n;
546
0
    }
547
0
    else {
548
0
  negative = 0;
549
0
        un = n;
550
0
    }
551
0
    *start = 0;
552
0
    do {
553
0
  *--start = (char)('0' + (un % 10));
554
0
  un /= 10;
555
0
    } while (un);
556
0
    if (negative) {
557
0
  *--start = '-';
558
0
    }
559
0
    return start;
560
0
}
561
562
APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n)
563
0
{
564
0
    const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2;
565
0
    char *buf = apr_palloc(p, BUFFER_SIZE);
566
0
    char *start = buf + BUFFER_SIZE - 1;
567
0
    int negative;
568
0
    if (n < 0) {
569
0
  negative = 1;
570
0
  n = -n;
571
0
    }
572
0
    else {
573
0
  negative = 0;
574
0
    }
575
0
    *start = 0;
576
0
    do {
577
0
  *--start = '0' + (char)(n % 10);
578
0
  n /= 10;
579
0
    } while (n);
580
0
    if (negative) {
581
0
  *--start = '-';
582
0
    }
583
0
    return start;
584
0
}
585
586
APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf)
587
0
{
588
0
    const char ord[] = "KMGTPE";
589
0
    const char *o = ord;
590
0
    int remain;
591
592
0
    if (size < 0) {
593
0
        return strcpy(buf, "  - ");
594
0
    }
595
0
    if (size < 973) {
596
0
        if (apr_snprintf(buf, 5, "%3d ", (int) size) < 0)
597
0
            return strcpy(buf, "****");
598
0
        return buf;
599
0
    }
600
0
    do {
601
0
        remain = (int)(size & 1023);
602
0
        size >>= 10;
603
0
        if (size >= 973) {
604
0
            ++o;
605
0
            continue;
606
0
        }
607
0
        if (size < 9 || (size == 9 && remain < 973)) {
608
0
            if ((remain = ((remain * 5) + 256) / 512) >= 10)
609
0
                ++size, remain = 0;
610
0
            if (apr_snprintf(buf, 5, "%d.%d%c", (int) size, remain, *o) < 0)
611
0
                return strcpy(buf, "****");
612
0
            return buf;
613
0
        }
614
0
        if (remain >= 512)
615
0
            ++size;
616
0
        if (apr_snprintf(buf, 5, "%3d%c", (int) size, *o) < 0)
617
0
            return strcpy(buf, "****");
618
0
        return buf;
619
0
    } while (1);
620
0
}
621