• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 9792155454

04 Jul 2024 09:39AM UTC coverage: 92.719% (+0.1%) from 92.612%
9792155454

push

github

Buristan
Avoid negation of signed integers in C that may hold INT*_MIN.

Reported by minoki.
Recent C compilers 'take advantage' of the undefined behavior.
This completely changes the meaning of expressions like (k == -k).

(cherry picked from commit 8a5e398c5)

This patch changes all possibly dangerous -x operations on integers to
the corresponding two's complement. Also, it removes all related UBSAN
suppressions, since they are fixed.

Also, this patch limits the `bit.tohex()` result by 254 characters.

There is no testcase for `strscan_oct()`, `strscan_dec()` or/and
`STRSCAN_U32` format since first the unary minus is parsed first and
only after the number itself is parsed during parsing C syntax. So the
error is raised in `cp_expr_prefix()` instead. For parsing the exponent
header, there is no testcase, since the power is limited by
`STRSCAN_MAXEXP`.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#9924
Relates to tarantool/tarantool#8473

Reviewed-by: Maxim Kokryashkin <m.kokryashkin@tarantool.org>
Reviewed-by: Sergey Bronnikov <sergeyb@tarantool.org>
Signed-off-by: Sergey Kaplun <skaplun@tarantool.org>

5673 of 6025 branches covered (94.16%)

Branch coverage included in aggregate %.

24 of 31 new or added lines in 10 files covered. (77.42%)

6 existing lines in 1 file now uncovered.

21641 of 23434 relevant lines covered (92.35%)

2953217.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.78
/src/lj_strscan.c
1
/*
2
** String scanning.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
*/
5

6
#include <math.h>
7

8
#define lj_strscan_c
9
#define LUA_CORE
10

11
#include "lj_obj.h"
12
#include "lj_char.h"
13
#include "lj_strscan.h"
14

15
/* -- Scanning numbers ---------------------------------------------------- */
16

17
/*
18
** Rationale for the builtin string to number conversion library:
19
**
20
** It removes a dependency on libc's strtod(), which is a true portability
21
** nightmare. Mainly due to the plethora of supported OS and toolchain
22
** combinations. Sadly, the various implementations
23
** a) are often buggy, incomplete (no hex floats) and/or imprecise,
24
** b) sometimes crash or hang on certain inputs,
25
** c) return non-standard NaNs that need to be filtered out, and
26
** d) fail if the locale-specific decimal separator is not a dot,
27
**    which can only be fixed with atrocious workarounds.
28
**
29
** Also, most of the strtod() implementations are hopelessly bloated,
30
** which is not just an I-cache hog, but a problem for static linkage
31
** on embedded systems, too.
32
**
33
** OTOH the builtin conversion function is very compact. Even though it
34
** does a lot more, like parsing long longs, octal or imaginary numbers
35
** and returning the result in different formats:
36
** a) It needs less than 3 KB (!) of machine code (on x64 with -Os),
37
** b) it doesn't perform any dynamic allocation and,
38
** c) it needs only around 600 bytes of stack space.
39
**
40
** The builtin function is faster than strtod() for typical inputs, e.g.
41
** "123", "1.5" or "1e6". Arguably, it's slower for very large exponents,
42
** which are not very common (this could be fixed, if needed).
43
**
44
** And most importantly, the builtin function is equally precise on all
45
** platforms. It correctly converts and rounds any input to a double.
46
** If this is not the case, please send a bug report -- but PLEASE verify
47
** that the implementation you're comparing to is not the culprit!
48
**
49
** The implementation quickly pre-scans the entire string first and
50
** handles simple integers on-the-fly. Otherwise, it dispatches to the
51
** base-specific parser. Hex and octal is straightforward.
52
**
53
** Decimal to binary conversion uses a fixed-length circular buffer in
54
** base 100. Some simple cases are handled directly. For other cases, the
55
** number in the buffer is up-scaled or down-scaled until the integer part
56
** is in the proper range. Then the integer part is rounded and converted
57
** to a double which is finally rescaled to the result. Denormals need
58
** special treatment to prevent incorrect 'double rounding'.
59
*/
60

61
/* Definitions for circular decimal digit buffer (base 100 = 2 digits/byte). */
62
#define STRSCAN_DIG        1024
63
#define STRSCAN_MAXDIG        800                /* 772 + extra are sufficient. */
64
#define STRSCAN_DDIG        (STRSCAN_DIG/2)
65
#define STRSCAN_DMASK        (STRSCAN_DDIG-1)
66
#define STRSCAN_MAXEXP        (1 << 20)
67

68
/* Helpers for circular buffer. */
69
#define DNEXT(a)        (((a)+1) & STRSCAN_DMASK)
70
#define DPREV(a)        (((a)-1) & STRSCAN_DMASK)
71
#define DLEN(lo, hi)        ((int32_t)(((lo)-(hi)) & STRSCAN_DMASK))
72

73
#define casecmp(c, k)        (((c) | 0x20) == k)
74

75
/* Final conversion to double. */
76
static void strscan_double(uint64_t x, TValue *o, int32_t ex2, int32_t neg)
77
{
78
  double n;
79

80
  /* Avoid double rounding for denormals. */
81
  if (LJ_UNLIKELY(ex2 <= -1075 && x != 0)) {
82
    /* NYI: all of this generates way too much code on 32 bit CPUs. */
83
#if (defined(__GNUC__) || defined(__clang__)) && LJ_64
84
    int32_t b = (int32_t)(__builtin_clzll(x)^63);
85
#else
86
    int32_t b = (x>>32) ? 32+(int32_t)lj_fls((uint32_t)(x>>32)) :
87
                          (int32_t)lj_fls((uint32_t)x);
88
#endif
89
    if ((int32_t)b + ex2 <= -1023 && (int32_t)b + ex2 >= -1075) {
90
      uint64_t rb = (uint64_t)1 << (-1075-ex2);
91
      if ((x & rb) && ((x & (rb+rb+rb-1)))) x += rb+rb;
92
      x = (x & ~(rb+rb-1));
93
    }
94
  }
95

96
  /* Convert to double using a signed int64_t conversion, then rescale. */
97
  lj_assertX((int64_t)x >= 0, "bad double conversion");
98
  n = (double)(int64_t)x;
99
  if (neg) n = -n;
100
  if (ex2) n = ldexp(n, ex2);
101
  o->n = n;
102
}
103

104
/* Parse hexadecimal number. */
105
static StrScanFmt strscan_hex(const uint8_t *p, TValue *o,
1,532✔
106
                              StrScanFmt fmt, uint32_t opt,
107
                              int32_t ex2, int32_t neg, uint32_t dig)
108
{
109
  uint64_t x = 0;
1,532✔
110
  uint32_t i;
1,532✔
111

112
  /* Scan hex digits. */
113
  for (i = dig > 16 ? 16 : dig ; i; i--, p++) {
12,045✔
114
    uint32_t d = (*p != '.' ? *p : *++p); if (d > '9') d += 9;
10,513✔
115
    x = (x << 4) + (d & 15);
10,513✔
116
  }
117

118
  /* Summarize rounding-effect of excess digits. */
119
  for (i = 16; i < dig; i++, p++)
1,532✔
120
    x |= ((*p != '.' ? *p : *++p) != '0'), ex2 += 4;
×
121

122
  /* Format-specific handling. */
123
  switch (fmt) {
1,532✔
124
  case STRSCAN_INT:
1,381✔
125
    if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg &&
1,381✔
126
        !(x == 0 && neg)) {
3✔
127
      o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
3✔
128
      return STRSCAN_INT;  /* Fast path for 32 bit integers. */
3✔
129
    }
130
    if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; }
1,378✔
131
    /* fallthrough */
132
  case STRSCAN_U32:
133
    if (dig > 8) return STRSCAN_ERROR;
4✔
134
    o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
4✔
135
    return STRSCAN_U32;
4✔
136
  case STRSCAN_I64:
101✔
137
  case STRSCAN_U64:
138
    if (dig > 16) return STRSCAN_ERROR;
101✔
139
    o->u64 = neg ? ~x+1u : x;
101✔
140
    return fmt;
101✔
141
  default:
142
    break;
143
  }
144

145
  /* Reduce range, then convert to double. */
146
  if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; }
1,424✔
147
  strscan_double(x, o, ex2, neg);
1,424✔
148
  return fmt;
1,424✔
149
}
150

151
/* Parse octal number. */
152
static StrScanFmt strscan_oct(const uint8_t *p, TValue *o,
13✔
153
                              StrScanFmt fmt, int32_t neg, uint32_t dig)
154
{
155
  uint64_t x = 0;
13✔
156

157
  /* Scan octal digits. */
158
  if (dig > 22 || (dig == 22 && *p > '1')) return STRSCAN_ERROR;
13✔
159
  while (dig-- > 0) {
13✔
160
    if (!(*p >= '0' && *p <= '7')) return STRSCAN_ERROR;
×
161
    x = (x << 3) + (*p++ & 7);
×
162
  }
163

164
  /* Format-specific handling. */
165
  switch (fmt) {
13✔
166
  case STRSCAN_INT:
13✔
167
    if (x >= 0x80000000u+neg) fmt = STRSCAN_U32;
13✔
168
    /* fallthrough */
169
  case STRSCAN_U32:
170
    if ((x >> 32)) return STRSCAN_ERROR;
13✔
171
    o->i = neg ? (int32_t)(~(uint32_t)x+1u) : (int32_t)x;
13✔
172
    break;
13✔
173
  default:
×
174
  case STRSCAN_I64:
175
  case STRSCAN_U64:
NEW
176
    o->u64 = neg ? ~x+1u : x;
×
177
    break;
×
178
  }
179
  return fmt;
180
}
181

182
/* Parse decimal number. */
183
static StrScanFmt strscan_dec(const uint8_t *p, TValue *o,
218,188✔
184
                              StrScanFmt fmt, uint32_t opt,
185
                              int32_t ex10, int32_t neg, uint32_t dig)
186
{
187
  uint8_t xi[STRSCAN_DDIG], *xip = xi;
218,188✔
188

189
  if (dig) {
218,188✔
190
    uint32_t i = dig;
218,095✔
191
    if (i > STRSCAN_MAXDIG) {
218,095✔
192
      ex10 += (int32_t)(i - STRSCAN_MAXDIG);
×
193
      i = STRSCAN_MAXDIG;
×
194
    }
195
    /* Scan unaligned leading digit. */
196
    if (((ex10^i) & 1))
218,095✔
197
      *xip++ = ((*p != '.' ? *p : *++p) & 15), i--, p++;
165,098✔
198
    /* Scan aligned double-digits. */
199
    for ( ; i > 1; i -= 2) {
623,614✔
200
      uint32_t d = 10 * ((*p != '.' ? *p : *++p) & 15); p++;
405,519✔
201
      *xip++ = d + ((*p != '.' ? *p : *++p) & 15); p++;
405,519✔
202
    }
203
    /* Scan and realign trailing digit. */
204
    if (i) *xip++ = 10 * ((*p != '.' ? *p : *++p) & 15), ex10--, dig++, p++;
218,095✔
205

206
    /* Summarize rounding-effect of excess digits. */
207
    if (dig > STRSCAN_MAXDIG) {
218,095✔
208
      do {
×
209
        if ((*p != '.' ? *p : *++p) != '0') { xip[-1] |= 1; break; }
×
210
        p++;
×
211
      } while (--dig > STRSCAN_MAXDIG);
×
212
      dig = STRSCAN_MAXDIG;
213
    } else {  /* Simplify exponent. */
214
      while (ex10 > 0 && dig <= 18) *xip++ = 0, ex10 -= 2, dig += 2;
270,565✔
215
    }
216
  } else {  /* Only got zeros. */
217
    ex10 = 0;
93✔
218
    xi[0] = 0;
93✔
219
  }
220

221
  /* Fast path for numbers in integer format (but handles e.g. 1e6, too). */
222
  if (dig <= 20 && ex10 == 0) {
218,188✔
223
    uint8_t *xis;
1,611✔
224
    uint64_t x = xi[0];
1,611✔
225
    double n;
1,611✔
226
    for (xis = xi+1; xis < xip; xis++) x = x * 100 + *xis;
5,806✔
227
    if (!(dig == 20 && (xi[0] > 18 || (int64_t)x >= 0))) {  /* No overflow? */
1,611✔
228
      /* Format-specific handling. */
229
      switch (fmt) {
1,611✔
230
      case STRSCAN_INT:
41✔
231
        if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) {
41✔
NEW
232
          o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
×
233
          return STRSCAN_INT;  /* Fast path for 32 bit integers. */
×
234
        }
235
        if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; goto plainnumber; }
41✔
236
        /* fallthrough */
237
      case STRSCAN_U32:
238
        if ((x >> 32) != 0) return STRSCAN_ERROR;
×
NEW
239
        o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
×
240
        return STRSCAN_U32;
×
241
      case STRSCAN_I64:
139✔
242
      case STRSCAN_U64:
243
        o->u64 = neg ? ~x+1u : x;
139✔
244
        return fmt;
139✔
245
      default:
246
      plainnumber:  /* Fast path for plain numbers < 2^63. */
1,472✔
247
        if ((int64_t)x < 0) break;
1,472✔
248
        n = (double)(int64_t)x;
1,457✔
249
        if (neg) n = -n;
1,457✔
250
        o->n = n;
1,457✔
251
        return fmt;
1,457✔
252
      }
253
    }
216,592✔
254
  }
255

256
  /* Slow non-integer path. */
257
  if (fmt == STRSCAN_INT) {
216,592✔
258
    if ((opt & STRSCAN_OPT_C)) return STRSCAN_ERROR;
×
259
    fmt = STRSCAN_NUM;
260
  } else if (fmt > STRSCAN_INT) {
216,592✔
261
    return STRSCAN_ERROR;
262
  }
263
  {
264
    uint32_t hi = 0, lo = (uint32_t)(xip-xi);
216,592✔
265
    int32_t ex2 = 0, idig = (int32_t)lo + (ex10 >> 1);
216,592✔
266

267
    lj_assertX(lo > 0 && (ex10 & 1) == 0, "bad lo %d ex10 %d", lo, ex10);
216,592✔
268

269
    /* Handle simple overflow/underflow. */
270
    if (idig > 310/2) { if (neg) setminfV(o); else setpinfV(o); return fmt; }
216,592✔
271
    else if (idig < -326/2) { o->n = neg ? -0.0 : 0.0; return fmt; }
216,588✔
272

273
    /* Scale up until we have at least 17 or 18 integer part digits. */
274
    while (idig < 9 && idig < DLEN(lo, hi)) {
1,136,874✔
275
      uint32_t i, cy = 0;
920,286✔
276
      ex2 -= 6;
920,286✔
277
      for (i = DPREV(lo); ; i = DPREV(i)) {
30,952,270✔
278
        uint32_t d = (xi[i] << 6) + cy;
30,952,270✔
279
        cy = (((d >> 2) * 5243) >> 17); d = d - cy * 100;  /* Div/mod 100. */
30,952,270✔
280
        xi[i] = (uint8_t)d;
30,952,270✔
281
        if (i == hi) break;
30,952,270✔
282
        if (d == 0 && i == DPREV(lo)) lo = i;
30,031,984✔
283
      }
284
      if (cy) {
920,286✔
285
        hi = DPREV(hi);
826,785✔
286
        if (xi[DPREV(lo)] == 0) lo = DPREV(lo);
826,785✔
287
        else if (hi == lo) { lo = DPREV(lo); xi[DPREV(lo)] |= xi[lo]; }
826,266✔
288
        xi[hi] = (uint8_t)cy; idig++;
826,785✔
289
      }
290
    }
291

292
    /* Scale down until no more than 17 or 18 integer part digits remain. */
293
    while (idig > 9) {
621,714✔
294
      uint32_t i = hi, cy = 0;
405,126✔
295
      ex2 += 6;
405,126✔
296
      do {
42,679,778✔
297
        cy += xi[i];
42,679,778✔
298
        xi[i] = (cy >> 6);
42,679,778✔
299
        cy = 100 * (cy & 0x3f);
42,679,778✔
300
        if (xi[i] == 0 && i == hi) hi = DNEXT(hi), idig--;
42,679,778✔
301
        i = DNEXT(i);
42,679,778✔
302
      } while (i != lo);
42,679,778✔
303
      while (cy) {
1,571,838✔
304
        if (hi == lo) { xi[DPREV(lo)] |= 1; break; }
1,166,712✔
305
        xi[lo] = (cy >> 6); lo = DNEXT(lo);
1,166,712✔
306
        cy = 100 * (cy & 0x3f);
1,166,712✔
307
      }
308
    }
309

310
    /* Collect integer part digits and convert to rescaled double. */
311
    {
312
      uint64_t x = xi[hi];
216,588✔
313
      uint32_t i;
216,588✔
314
      for (i = DNEXT(hi); --idig > 0 && i != lo; i = DNEXT(i))
913,243✔
315
        x = x * 100 + xi[i];
696,655✔
316
      if (i == lo) {
216,588✔
317
        while (--idig >= 0) x = x * 100;
200,543✔
318
      } else {  /* Gather round bit from remaining digits. */
319
        x <<= 1; ex2--;
24,167✔
320
        do {
24,243✔
321
          if (xi[i]) { x |= 1; break; }
24,243✔
322
          i = DNEXT(i);
76✔
323
        } while (i != lo);
76✔
324
      }
325
      strscan_double(x, o, ex2, neg);
216,588✔
326
    }
327
  }
328
  return fmt;
216,588✔
329
}
330

331
/* Parse binary number. */
332
static StrScanFmt strscan_bin(const uint8_t *p, TValue *o,
1✔
333
                              StrScanFmt fmt, uint32_t opt,
334
                              int32_t ex2, int32_t neg, uint32_t dig)
335
{
336
  uint64_t x = 0;
1✔
337
  uint32_t i;
1✔
338

339
  if (ex2 || dig > 64) return STRSCAN_ERROR;
1✔
340

341
  /* Scan binary digits. */
342
  for (i = dig; i; i--, p++) {
33✔
343
    if ((*p & ~1) != '0') return STRSCAN_ERROR;
32✔
344
    x = (x << 1) | (*p & 1);
32✔
345
  }
346

347
  /* Format-specific handling. */
348
  switch (fmt) {
1✔
349
  case STRSCAN_INT:
1✔
350
    if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) {
1✔
NEW
351
      o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
×
352
      return STRSCAN_INT;  /* Fast path for 32 bit integers. */
×
353
    }
354
    if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; }
1✔
355
    /* fallthrough */
356
  case STRSCAN_U32:
357
    if (dig > 32) return STRSCAN_ERROR;
×
NEW
358
    o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
×
359
    return STRSCAN_U32;
×
360
  case STRSCAN_I64:
×
361
  case STRSCAN_U64:
NEW
362
    o->u64 = neg ? ~x+1u : x;
×
363
    return fmt;
×
364
  default:
365
    break;
366
  }
367

368
  /* Reduce range, then convert to double. */
369
  if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; }
1✔
370
  strscan_double(x, o, ex2, neg);
1✔
371
  return fmt;
1✔
372
}
373

374
/* Scan string containing a number. Returns format. Returns value in o. */
375
StrScanFmt lj_strscan_scan(const uint8_t *p, MSize len, TValue *o,
731,357✔
376
                           uint32_t opt)
377
{
378
  int32_t neg = 0;
731,357✔
379
  const uint8_t *pe = p + len;
731,357✔
380

381
  /* Remove leading space, parse sign and non-numbers. */
382
  if (LJ_UNLIKELY(!lj_char_isdigit(*p))) {
731,357✔
383
    while (lj_char_isspace(*p)) p++;
350✔
384
    if (*p == '+' || *p == '-') neg = (*p++ == '-');
322✔
385
    if (LJ_UNLIKELY(*p >= 'A')) {  /* Parse "inf", "infinity" or "nan". */
322✔
386
      TValue tmp;
49✔
387
      setnanV(&tmp);
49✔
388
      if (casecmp(p[0],'i') && casecmp(p[1],'n') && casecmp(p[2],'f')) {
49✔
389
        if (neg) setminfV(&tmp); else setpinfV(&tmp);
×
390
        p += 3;
×
391
        if (casecmp(p[0],'i') && casecmp(p[1],'n') && casecmp(p[2],'i') &&
×
392
            casecmp(p[3],'t') && casecmp(p[4],'y')) p += 5;
×
393
      } else if (casecmp(p[0],'n') && casecmp(p[1],'a') && casecmp(p[2],'n')) {
49✔
394
        p += 3;
1✔
395
      }
396
      while (lj_char_isspace(*p)) p++;
49✔
397
      if (*p || p < pe) return STRSCAN_ERROR;
49✔
398
      o->u64 = tmp.u64;
1✔
399
      return STRSCAN_NUM;
1✔
400
    }
401
  }
402

403
  /* Parse regular number. */
404
  {
405
    StrScanFmt fmt = STRSCAN_INT;
731,308✔
406
    int cmask = LJ_CHAR_DIGIT;
731,308✔
407
    int base = (opt & STRSCAN_OPT_C) && *p == '0' ? 0 : 10;
731,308✔
408
    const uint8_t *sp, *dp = NULL;
731,308✔
409
    uint32_t dig = 0, hasdig = 0, x = 0;
731,308✔
410
    int32_t ex = 0;
731,308✔
411

412
    /* Determine base and skip leading zeros. */
413
    if (LJ_UNLIKELY(*p <= '0')) {
731,308✔
414
      if (*p == '0') {
16,965✔
415
        if (casecmp(p[1], 'x'))
16,747✔
416
          base = 16, cmask = LJ_CHAR_XDIGIT, p += 2;
1,533✔
417
        else if (casecmp(p[1], 'b'))
15,214✔
418
          base = 2, cmask = LJ_CHAR_DIGIT, p += 2;
3✔
419
      }
420
      for ( ; ; p++) {
3,122,187✔
421
        if (*p == '0') {
3,139,152✔
422
          hasdig = 1;
423
        } else if (*p == '.') {
24,648✔
424
          if (dp) return STRSCAN_ERROR;
7,683✔
425
          dp = p;
426
        } else {
427
          break;
428
        }
429
      }
430
    }
431

432
    /* Preliminary digit and decimal point scan. */
433
    for (sp = p; ; p++) {
2,886,629✔
434
      if (LJ_LIKELY(lj_char_isa(*p, cmask))) {
2,886,629✔
435
        x = x * 10 + (*p & 15);  /* For fast path below. */
1,960,726✔
436
        dig++;
1,960,726✔
437
      } else if (*p == '.') {
925,903✔
438
        if (dp) return STRSCAN_ERROR;
194,596✔
439
        dp = p;
440
      } else {
441
        break;
442
      }
443
    }
444
    if (!(hasdig | dig)) return STRSCAN_ERROR;
731,307✔
445

446
    /* Handle decimal point. */
447
    if (dp) {
731,301✔
448
      if (base == 2) return STRSCAN_ERROR;
202,275✔
449
      fmt = STRSCAN_NUM;
202,273✔
450
      if (dig) {
202,273✔
451
        ex = (int32_t)(dp-(p-1)); dp = p-1;
202,221✔
452
        while (ex < 0 && *dp-- == '0') ex++, dig--;  /* Skip trailing zeros. */
202,402✔
453
        if (ex <= -STRSCAN_MAXEXP) return STRSCAN_ERROR;
202,221✔
454
        if (base == 16) ex *= 4;
202,219✔
455
      }
456
    }
457

458
    /* Parse exponent. */
459
    if (base >= 10 && casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) {
1,461,047✔
460
      uint32_t xx;
18,427✔
461
      int negx = 0;
18,427✔
462
      fmt = STRSCAN_NUM; p++;
18,427✔
463
      if (*p == '+' || *p == '-') negx = (*p++ == '-');
18,427✔
464
      if (!lj_char_isdigit(*p)) return STRSCAN_ERROR;
18,427✔
465
      xx = (*p++ & 15);
18,371✔
466
      while (lj_char_isdigit(*p)) {
46,190✔
467
        xx = xx * 10 + (*p & 15);
27,819✔
468
        if (xx >= STRSCAN_MAXEXP) return STRSCAN_ERROR;
27,819✔
469
        p++;
27,819✔
470
      }
471
      ex += negx ? (int32_t)(~xx+1u) : (int32_t)xx;
18,371✔
472
    }
473

474
    /* Parse suffix. */
475
    if (*p) {
731,241✔
476
      /* I (IMAG), U (U32), LL (I64), ULL/LLU (U64), L (long), UL/LU (ulong). */
477
      /* NYI: f (float). Not needed until cp_number() handles non-integers. */
478
      if (casecmp(*p, 'i')) {
287✔
479
        if (!(opt & STRSCAN_OPT_IMAG)) return STRSCAN_ERROR;
19✔
480
        p++; fmt = STRSCAN_IMAG;
18✔
481
      } else if (fmt == STRSCAN_INT) {
268✔
482
        if (casecmp(*p, 'u')) p++, fmt = STRSCAN_U32;
257✔
483
        if (casecmp(*p, 'l')) {
257✔
484
          p++;
244✔
485
          if (casecmp(*p, 'l')) p++, fmt += STRSCAN_I64 - STRSCAN_INT;
244✔
486
          else if (!(opt & STRSCAN_OPT_C)) return STRSCAN_ERROR;
2✔
487
          else if (sizeof(long) == 8) fmt += STRSCAN_I64 - STRSCAN_INT;
×
488
        }
489
        if (casecmp(*p, 'u') && (fmt == STRSCAN_INT || fmt == STRSCAN_I64))
255✔
490
          p++, fmt += STRSCAN_U32 - STRSCAN_INT;
1✔
491
        if ((fmt == STRSCAN_U32 && !(opt & STRSCAN_OPT_C)) ||
255✔
492
            (fmt >= STRSCAN_I64 && !(opt & STRSCAN_OPT_LL)))
242✔
493
          return STRSCAN_ERROR;
494
      }
495
      while (lj_char_isspace(*p)) p++;
307✔
496
      if (*p) return STRSCAN_ERROR;
283✔
497
    }
498
    if (p < pe) return STRSCAN_ERROR;
731,228✔
499

500
    /* Fast path for decimal 32 bit integers. */
501
    if (fmt == STRSCAN_INT && base == 10 &&
731,227✔
502
        (dig < 10 || (dig == 10 && *sp <= '2' && x < 0x80000000u+neg))) {
119✔
503
      if ((opt & STRSCAN_OPT_TONUM)) {
511,493✔
504
        o->n = neg ? -(double)x : (double)x;
511,032✔
505
        return STRSCAN_NUM;
511,032✔
506
      } else if (x == 0 && neg) {
461✔
507
        o->n = -0.0;
×
508
        return STRSCAN_NUM;
×
509
      } else {
510
        o->i = neg ? (int32_t)(~x+1u) : (int32_t)x;
461✔
511
        return STRSCAN_INT;
461✔
512
      }
513
    }
514

515
    /* Dispatch to base-specific parser. */
516
    if (base == 0 && !(fmt == STRSCAN_NUM || fmt == STRSCAN_IMAG))
219,734✔
517
      return strscan_oct(sp, o, fmt, neg, dig);
13✔
518
    if (base == 16)
219,721✔
519
      fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig);
1,532✔
520
    else if (base == 2)
218,189✔
521
      fmt = strscan_bin(sp, o, fmt, opt, ex, neg, dig);
1✔
522
    else
523
      fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig);
218,188✔
524

525
    /* Try to convert number to integer, if requested. */
526
    if (fmt == STRSCAN_NUM && (opt & STRSCAN_OPT_TOINT) && !tvismzero(o)) {
219,721✔
527
      double n = o->n;
×
528
      int32_t i = lj_num2int(n);
×
529
      if (n == (lua_Number)i) { o->i = i; return STRSCAN_INT; }
×
530
    }
531
    return fmt;
532
  }
533
}
534

535
int LJ_FASTCALL lj_strscan_num(GCstr *str, TValue *o)
22,500✔
536
{
537
  StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), str->len, o,
22,500✔
538
                                   STRSCAN_OPT_TONUM);
539
  lj_assertX(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM, "bad scan format");
22,500✔
540
  return (fmt != STRSCAN_ERROR);
22,500✔
541
}
542

543
#if LJ_DUALNUM
544
int LJ_FASTCALL lj_strscan_number(GCstr *str, TValue *o)
545
{
546
  StrScanFmt fmt = lj_strscan_scan((const uint8_t *)strdata(str), str->len, o,
547
                                   STRSCAN_OPT_TOINT);
548
  lj_assertX(fmt == STRSCAN_ERROR || fmt == STRSCAN_NUM || fmt == STRSCAN_INT,
549
             "bad scan format");
550
  if (fmt == STRSCAN_INT) setitype(o, LJ_TISNUM);
551
  return (fmt != STRSCAN_ERROR);
552
}
553
#endif
554

555
#undef DNEXT
556
#undef DPREV
557
#undef DLEN
558

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc