Coverage Report

Created: 2025-10-28 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/strnum.c
Line
Count
Source
1
/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "strnum.h"
5
6
bool str_is_numeric(const char *str, char end_char)
7
0
{
8
0
  if (*str == '\0' || *str == end_char)
9
0
    return FALSE;
10
11
0
  while (*str != '\0' && *str != end_char) {
12
0
    if (*str < '0' || *str > '9')
13
0
      return FALSE;
14
0
    str++;
15
0
  }
16
17
0
  return TRUE;
18
0
}
19
20
bool str_is_float(const char *str, char end_char)
21
0
{
22
0
  bool dot_seen = FALSE;
23
0
  bool num_seen = FALSE;
24
25
0
  if (*str == '\0' || *str == end_char)
26
0
    return FALSE;
27
28
0
  while (*str != '\0' && *str != end_char) {
29
0
    if (*str == '.') {
30
0
      if (dot_seen || !num_seen) return FALSE;
31
0
      dot_seen = TRUE;
32
0
      num_seen = FALSE;
33
0
      str++;
34
      /* enforce that number follows dot */
35
0
      continue;
36
0
    }
37
0
    if (*str < '0' || *str > '9')
38
0
      return FALSE;
39
0
    num_seen = TRUE;
40
0
    str++;
41
0
  }
42
43
0
  return num_seen;
44
0
}
45
46
/*
47
 * Unsigned decimal
48
 */
49
50
#define STR_PARSE_U__TEMPLATE(name, type)                     \
51
0
int name(const char *str, type *num_r, const char **endp_r)   \
52
0
{                                                             \
53
0
  uintmax_t l;                                                \
54
0
  if (str_parse_uintmax(str, &l, endp_r) < 0 || l > (type)-1) \
55
0
    return -1;                                                \
56
0
  *num_r = (type)l;                                           \
57
0
  return 0;                                                   \
58
0
}
Unexecuted instantiation: str_parse_uint
Unexecuted instantiation: str_parse_ulong
Unexecuted instantiation: str_parse_ullong
Unexecuted instantiation: str_parse_uint32
Unexecuted instantiation: str_parse_uint64
Unexecuted instantiation: str_parse_uoff
59
60
STR_PARSE_U__TEMPLATE(str_parse_uint, unsigned int)
61
STR_PARSE_U__TEMPLATE(str_parse_ulong, unsigned long)
62
STR_PARSE_U__TEMPLATE(str_parse_ullong, unsigned long long)
63
STR_PARSE_U__TEMPLATE(str_parse_uint32, uint32_t)
64
STR_PARSE_U__TEMPLATE(str_parse_uint64, uint64_t)
65
66
#define STR_TO_U__TEMPLATE(name, type)                        \
67
0
int name(const char *str, type *num_r)                        \
68
0
{                                                             \
69
0
  uintmax_t l;                                                \
70
0
  if (str_to_uintmax(str, &l) < 0 || l > (type)-1)            \
71
0
    return -1;                                                \
72
0
  *num_r = (type)l;                                           \
73
0
  return 0;                                                   \
74
0
}
Unexecuted instantiation: str_to_uint
Unexecuted instantiation: str_to_ulong
Unexecuted instantiation: str_to_ullong
Unexecuted instantiation: str_to_uint32
Unexecuted instantiation: str_to_uint64
75
76
STR_TO_U__TEMPLATE(str_to_uint, unsigned int)
77
STR_TO_U__TEMPLATE(str_to_ulong, unsigned long)
78
STR_TO_U__TEMPLATE(str_to_ullong, unsigned long long)
79
STR_TO_U__TEMPLATE(str_to_uint32, uint32_t)
80
STR_TO_U__TEMPLATE(str_to_uint64, uint64_t)
81
82
int str_parse_data_uintmax(const unsigned char *data, size_t size,
83
         uintmax_t *num_r, const unsigned char **endp_r)
84
0
{
85
0
  const unsigned char *p = data, *pend = data + size;
86
0
  uintmax_t n = 0;
87
88
0
  if (p >= pend || *p < '0' || *p > '9')
89
0
    return -1;
90
91
0
  do {
92
0
    if (n >= ((uintmax_t)-1 / 10)) {
93
0
      if (n > (uintmax_t)-1 / 10)
94
0
        return -1;
95
0
      if ((uintmax_t)(*p - '0') > ((uintmax_t)-1 % 10))
96
0
        return -1;
97
0
    }
98
0
    n = n * 10 + (*p - '0');
99
0
    p++;
100
0
  } while (p < pend && *p >= '0' && *p <= '9');
101
102
0
  if (endp_r != NULL)
103
0
    *endp_r = p;
104
0
  *num_r = n;
105
0
  return 0;
106
0
}
107
int str_parse_uintmax(const char *str, uintmax_t *num_r, const char **endp_r)
108
0
{
109
0
  return str_parse_data_uintmax((const unsigned char *)str, strlen(str),
110
0
              num_r, (const unsigned char **)endp_r);
111
0
}
112
int str_to_uintmax(const char *str, uintmax_t *num_r)
113
0
{
114
0
  const char *endp = NULL;
115
0
  uintmax_t n;
116
0
  int ret = str_parse_uintmax(str, &n, &endp);
117
0
  if ((ret != 0) || (*endp != '\0'))
118
0
    return -1;
119
0
  *num_r = n;
120
0
  return 0;
121
0
}
122
123
bool str_uint_equals(const char *str, uintmax_t num)
124
0
{
125
0
  uintmax_t l;
126
127
0
  if (str_to_uintmax(str, &l) < 0)
128
0
    return FALSE;
129
0
  return l == num;
130
0
}
131
132
/*
133
 * Unsigned hexadecimal
134
 */
135
136
#define STR_PARSE_UHEX__TEMPLATE(name, type)                       \
137
0
int name(const char *str, type *num_r, const char **endp_r)        \
138
0
{                                                                  \
139
0
  uintmax_t l;                                                     \
140
0
  if (str_parse_uintmax_hex(str, &l, endp_r) < 0 || l > (type)-1)  \
141
0
    return -1;                                                     \
142
0
  *num_r = (type)l;                                                \
143
0
  return 0;                                                        \
144
0
}
Unexecuted instantiation: str_parse_uint_hex
Unexecuted instantiation: str_parse_ulong_hex
Unexecuted instantiation: str_parse_ullong_hex
Unexecuted instantiation: str_parse_uint32_hex
Unexecuted instantiation: str_parse_uint64_hex
145
146
STR_PARSE_UHEX__TEMPLATE(str_parse_uint_hex, unsigned int)
147
STR_PARSE_UHEX__TEMPLATE(str_parse_ulong_hex, unsigned long)
148
STR_PARSE_UHEX__TEMPLATE(str_parse_ullong_hex, unsigned long long)
149
STR_PARSE_UHEX__TEMPLATE(str_parse_uint32_hex, uint32_t)
150
STR_PARSE_UHEX__TEMPLATE(str_parse_uint64_hex, uint64_t)
151
152
#define STR_TO_UHEX__TEMPLATE(name, type)                          \
153
0
int name(const char *str, type *num_r)                             \
154
0
{                                                                  \
155
0
  uintmax_t l;                                                     \
156
0
  if (str_to_uintmax_hex(str, &l) < 0 || l > (type)-1)             \
157
0
    return -1;                                                     \
158
0
  *num_r = (type)l;                                                \
159
0
  return 0;                                                        \
160
0
}
Unexecuted instantiation: str_to_uint_hex
Unexecuted instantiation: str_to_ulong_hex
Unexecuted instantiation: str_to_ullong_hex
Unexecuted instantiation: str_to_uint32_hex
Unexecuted instantiation: str_to_uint64_hex
161
162
STR_TO_UHEX__TEMPLATE(str_to_uint_hex, unsigned int)
163
STR_TO_UHEX__TEMPLATE(str_to_ulong_hex, unsigned long)
164
STR_TO_UHEX__TEMPLATE(str_to_ullong_hex, unsigned long long)
165
STR_TO_UHEX__TEMPLATE(str_to_uint32_hex, uint32_t)
166
STR_TO_UHEX__TEMPLATE(str_to_uint64_hex, uint64_t)
167
168
static inline int _str_parse_hex(const char ch,
169
  unsigned int *hex_r)
170
0
{
171
0
  switch (ch) {
172
0
  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
173
0
    *hex_r = (unsigned int)(ch - 'a' + 10);
174
0
    return 0;
175
0
  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
176
0
    *hex_r = (unsigned int)(ch - 'A' + 10);
177
0
    return 0;
178
0
  case '0': case '1': case '2': case '3': case '4':
179
0
  case '5': case '6': case '7': case '8': case '9':
180
0
    *hex_r = (unsigned int)(ch - '0');
181
0
    return 0;
182
0
  default:
183
0
    break;
184
0
  }
185
0
  return -1;
186
0
}
187
int str_parse_uintmax_hex(const char *str, uintmax_t *num_r,
188
  const char **endp_r)
189
0
{
190
0
  unsigned int hex;
191
0
  uintmax_t n = 0;
192
193
0
  if (_str_parse_hex(*str, &hex) < 0)
194
0
    return -1;
195
196
0
  do {
197
0
    if (n > (uintmax_t)-1 >> 4)
198
0
      return -1;
199
0
    n = (n << 4) + hex;
200
0
    str++;
201
0
  } while (_str_parse_hex(*str, &hex) >= 0);
202
0
  if (endp_r != NULL)
203
0
    *endp_r = str;
204
0
  *num_r = n;
205
0
  return 0;
206
0
}
207
int str_to_uintmax_hex(const char *str, uintmax_t *num_r)
208
0
{
209
0
  const char *endp = NULL;
210
0
  uintmax_t n;
211
0
  int ret = str_parse_uintmax_hex(str, &n, &endp);
212
0
  if ((ret != 0) || (*endp != '\0'))
213
0
    return -1;
214
0
  *num_r = n;
215
0
  return 0;
216
0
}
217
218
/*
219
 * Unsigned octal
220
 */
221
222
#define STR_PARSE_UOCT__TEMPLATE(name, type)                       \
223
0
int name(const char *str, type *num_r, const char **endp_r)        \
224
0
{                                                                  \
225
0
  uintmax_t l;                                                     \
226
0
  if (str_parse_uintmax_oct(str, &l, endp_r) < 0 || l > (type)-1)  \
227
0
    return -1;                                                     \
228
0
  *num_r = (type)l;                                                \
229
0
  return 0;                                                        \
230
0
}
Unexecuted instantiation: str_parse_uint_oct
Unexecuted instantiation: str_parse_ulong_oct
Unexecuted instantiation: str_parse_ullong_oct
Unexecuted instantiation: str_parse_uint32_oct
Unexecuted instantiation: str_parse_uint64_oct
231
232
STR_PARSE_UOCT__TEMPLATE(str_parse_uint_oct, unsigned int)
233
STR_PARSE_UOCT__TEMPLATE(str_parse_ulong_oct, unsigned long)
234
STR_PARSE_UOCT__TEMPLATE(str_parse_ullong_oct, unsigned long long)
235
STR_PARSE_UOCT__TEMPLATE(str_parse_uint32_oct, uint32_t)
236
STR_PARSE_UOCT__TEMPLATE(str_parse_uint64_oct, uint64_t)
237
238
#define STR_TO_UOCT__TEMPLATE(name, type)                          \
239
0
int name(const char *str, type *num_r)                             \
240
0
{                                                                  \
241
0
  uintmax_t l;                                                     \
242
0
  if (str_to_uintmax_oct(str, &l) < 0 || l > (type)-1)             \
243
0
    return -1;                                                     \
244
0
  *num_r = (type)l;                                                \
245
0
  return 0;                                                        \
246
0
}
Unexecuted instantiation: str_to_uint_oct
Unexecuted instantiation: str_to_ulong_oct
Unexecuted instantiation: str_to_ullong_oct
Unexecuted instantiation: str_to_uint32_oct
Unexecuted instantiation: str_to_uint64_oct
247
248
STR_TO_UOCT__TEMPLATE(str_to_uint_oct, unsigned int)
249
STR_TO_UOCT__TEMPLATE(str_to_ulong_oct, unsigned long)
250
STR_TO_UOCT__TEMPLATE(str_to_ullong_oct, unsigned long long)
251
STR_TO_UOCT__TEMPLATE(str_to_uint32_oct, uint32_t)
252
STR_TO_UOCT__TEMPLATE(str_to_uint64_oct, uint64_t)
253
254
int str_parse_uintmax_oct(const char *str, uintmax_t *num_r,
255
  const char **endp_r)
256
0
{
257
0
  uintmax_t n = 0;
258
259
0
  if (*str < '0' || *str > '7')
260
0
    return -1;
261
262
0
  for (; *str >= '0' && *str <= '7'; str++) {
263
0
    if (n > (uintmax_t)-1 >> 3)
264
0
      return -1;
265
0
    n = (n << 3) + (*str - '0');
266
0
  }
267
0
  if (endp_r != NULL)
268
0
    *endp_r = str;
269
0
  *num_r = n;
270
0
  return 0;
271
0
}
272
int str_to_uintmax_oct(const char *str, uintmax_t *num_r)
273
0
{
274
0
  const char *endp = NULL;
275
0
  uintmax_t n;
276
0
  int ret = str_parse_uintmax_oct(str, &n, &endp);
277
0
  if ((ret != 0) || (*endp != '\0'))
278
0
    return -1;
279
0
  *num_r = n;
280
0
  return 0;
281
0
}
282
283
/*
284
 * Signed
285
 */
286
287
#define STR_PARSE_S__TEMPLATE(name, type, int_min, int_max)   \
288
0
int name(const char *str, type *num_r, const char **endp_r)   \
289
0
{                                                             \
290
0
  intmax_t l;                                                 \
291
0
  if (str_parse_intmax(str, &l, endp_r) < 0)                  \
292
0
    return -1;                                                \
293
0
  if (l < int_min || l > int_max)                             \
294
0
    return -1;                                                \
295
0
  *num_r = (type)l;                                           \
296
0
  return 0;                                                   \
297
0
}
Unexecuted instantiation: str_parse_int
Unexecuted instantiation: str_parse_long
Unexecuted instantiation: str_parse_llong
Unexecuted instantiation: str_parse_int32
Unexecuted instantiation: str_parse_int64
298
299
STR_PARSE_S__TEMPLATE(str_parse_int, int, INT_MIN, INT_MAX)
300
STR_PARSE_S__TEMPLATE(str_parse_long, long, LONG_MIN, LONG_MAX)
301
STR_PARSE_S__TEMPLATE(str_parse_llong, long long, LLONG_MIN, LLONG_MAX)
302
STR_PARSE_S__TEMPLATE(str_parse_int32, int32_t, INT32_MIN, INT32_MAX)
303
STR_PARSE_S__TEMPLATE(str_parse_int64, int64_t, INT64_MIN, INT64_MAX)
304
305
#define STR_TO_S__TEMPLATE(name, type, int_min, int_max)      \
306
0
int name(const char *str, type *num_r)                        \
307
0
{                                                             \
308
0
  intmax_t l;                                                 \
309
0
  if (str_to_intmax(str, &l) < 0)                             \
310
0
    return -1;                                                \
311
0
  if (l < int_min || l > int_max)                             \
312
0
    return -1;                                                \
313
0
  *num_r = (type)l;                                           \
314
0
  return 0;                                                   \
315
0
}
Unexecuted instantiation: str_to_int
Unexecuted instantiation: str_to_long
Unexecuted instantiation: str_to_llong
Unexecuted instantiation: str_to_int32
Unexecuted instantiation: str_to_int64
316
317
STR_TO_S__TEMPLATE(str_to_int, int, INT_MIN, INT_MAX)
318
STR_TO_S__TEMPLATE(str_to_long, long, LONG_MIN, LONG_MAX)
319
STR_TO_S__TEMPLATE(str_to_llong, long long, LLONG_MIN, LLONG_MAX)
320
STR_TO_S__TEMPLATE(str_to_int32, int32_t, INT32_MIN, INT32_MAX)
321
STR_TO_S__TEMPLATE(str_to_int64, int64_t, INT64_MIN, INT64_MAX)
322
323
int ATTR_NO_SANITIZE_IMPLICIT_CONVERSION ATTR_NO_SANITIZE_INTEGER
324
str_parse_intmax(const char *str, intmax_t *num_r, const char **endp_r)
325
0
{
326
0
  bool neg = FALSE;
327
0
  uintmax_t l;
328
329
0
  if (*str == '-') {
330
0
    neg = TRUE;
331
0
    str++;
332
0
  }
333
0
  if (str_parse_uintmax(str, &l, endp_r) < 0)
334
0
    return -1;
335
336
0
  if (!neg) {
337
0
    if (l > INTMAX_MAX)
338
0
      return -1;
339
0
    *num_r = (intmax_t)l;
340
0
  } else {
341
0
    if (l > UINTMAX_MAX - (UINTMAX_MAX + INTMAX_MIN))
342
0
      return -1;
343
0
    *num_r = (intmax_t) UNSIGNED_MINUS(l);
344
0
  }
345
0
  return 0;
346
0
}
347
int str_to_intmax(const char *str, intmax_t *num_r)
348
0
{
349
0
  const char *endp = NULL;
350
0
  intmax_t n;
351
0
  int ret = str_parse_intmax(str, &n, &endp);
352
0
  if ((ret != 0) || (*endp != '\0'))
353
0
    return -1;
354
0
  *num_r = n;
355
0
  return 0;
356
0
}
357
358
/*
359
 * Special numeric types
360
 */
361
362
static int verify_xid(uintmax_t l, unsigned int result_size)
363
0
{
364
0
  unsigned int result_bits;
365
366
  /* we assume that result is a signed type,
367
     but that it can never be negative */
368
0
  result_bits = result_size*CHAR_BIT - 1;
369
0
  if ((l >> result_bits) != 0)
370
0
    return -1;
371
0
  return 0;
372
0
}
373
374
int str_to_uid(const char *str, uid_t *num_r)
375
0
{
376
0
  uintmax_t l;
377
378
0
  if (str_to_uintmax(str, &l) < 0)
379
0
    return -1;
380
381
0
  if (verify_xid(l, sizeof(*num_r)) < 0)
382
0
    return -1;
383
0
  *num_r = (uid_t)l;
384
0
  return 0;
385
0
}
386
387
int str_to_gid(const char *str, gid_t *num_r)
388
0
{
389
0
  uintmax_t l;
390
391
0
  if (str_to_uintmax(str, &l) < 0)
392
0
    return -1;
393
394
  /* OS X uses negative GIDs */
395
0
#ifndef __APPLE__
396
0
  if (verify_xid(l, sizeof(*num_r)) < 0)
397
0
    return -1;
398
0
#endif
399
0
  *num_r = (gid_t)l;
400
0
  return 0;
401
0
}
402
403
int str_to_pid(const char *str, pid_t *num_r)
404
0
{
405
0
  uintmax_t l;
406
407
0
  if (str_to_uintmax(str, &l) < 0)
408
0
    return -1;
409
410
0
  if (verify_xid(l, sizeof(*num_r)) < 0)
411
0
    return -1;
412
0
  *num_r = (pid_t)l;
413
0
  return 0;
414
0
}
415
416
int str_to_ino(const char *str, ino_t *num_r)
417
0
{
418
0
  uintmax_t l;
419
420
0
  if (str_to_uintmax(str, &l) < 0)
421
0
    return -1;
422
423
0
  if (verify_xid(l, sizeof(*num_r)) < 0)
424
0
    return -1;
425
0
  *num_r = (ino_t)l;
426
0
  return 0;
427
0
}
428
429
int str_to_uoff(const char *str, uoff_t *num_r)
430
0
{
431
0
  uintmax_t l;
432
433
0
  if (str_to_uintmax(str, &l) < 0)
434
0
    return -1;
435
436
0
  if (l > UOFF_T_MAX)
437
0
    return -1;
438
0
  *num_r = (uoff_t)l;
439
0
  return 0;
440
0
}
441
442
int str_to_time(const char *str, time_t *num_r)
443
0
{
444
0
  intmax_t l;
445
446
0
  if (str_to_intmax(str, &l) < 0)
447
0
    return -1;
448
449
0
  *num_r = (time_t)l;
450
0
  return 0;
451
0
}
452
453
STR_PARSE_U__TEMPLATE(str_parse_uoff, uoff_t)
454
455
/*
456
 * Floating point types
457
 */
458
459
int str_to_float(const char *str, float *num_r)
460
0
{
461
0
  char *endp;
462
0
  float num = strtof(str, &endp);
463
0
  if (*endp != '\0')
464
0
    return -1;
465
466
0
  *num_r = num;
467
0
  return 0;
468
0
}
469
470
int str_to_double(const char *str, double *num_r)
471
0
{
472
0
  char *endp;
473
0
  double num = strtod(str, &endp);
474
0
  if (*endp != '\0')
475
0
    return -1;
476
477
0
  *num_r = num;
478
0
  return 0;
479
0
}
480
481
/*
482
 * Error handling
483
 */
484
485
const char *str_num_error(const char *str)
486
0
{
487
0
  if (*str == '-') {
488
0
    if (!str_is_numeric(str + 1, '\0'))
489
0
      return "Not a valid number";
490
0
    return "Number too small";
491
0
  } else {
492
0
    if (!str_is_numeric(str, '\0'))
493
0
      return "Not a valid number";
494
0
    return "Number too large";
495
0
  }
496
0
}