LCOV - code coverage report
Current view: top level - Python - mystrtoul.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 67 115 58.3 %
Date: 2022-07-07 18:19:46 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "Python.h"
       2             : #include "pycore_long.h"          // _PyLong_DigitValue
       3             : 
       4             : #if defined(__sgi) && !defined(_SGI_MP_SOURCE)
       5             : #define _SGI_MP_SOURCE
       6             : #endif
       7             : 
       8             : /* strtol and strtoul, renamed to avoid conflicts */
       9             : 
      10             : 
      11             : #include <ctype.h>
      12             : #ifdef HAVE_ERRNO_H
      13             : #include <errno.h>
      14             : #endif
      15             : 
      16             : /* Static overflow check values for bases 2 through 36.
      17             :  * smallmax[base] is the largest unsigned long i such that
      18             :  * i * base doesn't overflow unsigned long.
      19             :  */
      20             : static const unsigned long smallmax[] = {
      21             :     0, /* bases 0 and 1 are invalid */
      22             :     0,
      23             :     ULONG_MAX / 2,
      24             :     ULONG_MAX / 3,
      25             :     ULONG_MAX / 4,
      26             :     ULONG_MAX / 5,
      27             :     ULONG_MAX / 6,
      28             :     ULONG_MAX / 7,
      29             :     ULONG_MAX / 8,
      30             :     ULONG_MAX / 9,
      31             :     ULONG_MAX / 10,
      32             :     ULONG_MAX / 11,
      33             :     ULONG_MAX / 12,
      34             :     ULONG_MAX / 13,
      35             :     ULONG_MAX / 14,
      36             :     ULONG_MAX / 15,
      37             :     ULONG_MAX / 16,
      38             :     ULONG_MAX / 17,
      39             :     ULONG_MAX / 18,
      40             :     ULONG_MAX / 19,
      41             :     ULONG_MAX / 20,
      42             :     ULONG_MAX / 21,
      43             :     ULONG_MAX / 22,
      44             :     ULONG_MAX / 23,
      45             :     ULONG_MAX / 24,
      46             :     ULONG_MAX / 25,
      47             :     ULONG_MAX / 26,
      48             :     ULONG_MAX / 27,
      49             :     ULONG_MAX / 28,
      50             :     ULONG_MAX / 29,
      51             :     ULONG_MAX / 30,
      52             :     ULONG_MAX / 31,
      53             :     ULONG_MAX / 32,
      54             :     ULONG_MAX / 33,
      55             :     ULONG_MAX / 34,
      56             :     ULONG_MAX / 35,
      57             :     ULONG_MAX / 36,
      58             : };
      59             : 
      60             : /* maximum digits that can't ever overflow for bases 2 through 36,
      61             :  * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
      62             :  * Note that this is pessimistic if sizeof(long) > 4.
      63             :  */
      64             : #if SIZEOF_LONG == 4
      65             : static const int digitlimit[] = {
      66             :     0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  /*  0 -  9 */
      67             :     9,  9,  8,  8,  8,  8,  8,  7,  7,  7,  /* 10 - 19 */
      68             :     7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  /* 20 - 29 */
      69             :     6,  6,  6,  6,  6,  6,  6};             /* 30 - 36 */
      70             : #elif SIZEOF_LONG == 8
      71             : /* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */
      72             : static const int digitlimit[] = {
      73             :          0,   0, 64, 40, 32, 27, 24, 22, 21, 20,  /*  0 -  9 */
      74             :     19,  18, 17, 17, 16, 16, 16, 15, 15, 15,  /* 10 - 19 */
      75             :     14,  14, 14, 14, 13, 13, 13, 13, 13, 13,  /* 20 - 29 */
      76             :     13,  12, 12, 12, 12, 12, 12};             /* 30 - 36 */
      77             : #else
      78             : #error "Need table for SIZEOF_LONG"
      79             : #endif
      80             : 
      81             : /*
      82             : **      strtoul
      83             : **              This is a general purpose routine for converting
      84             : **              an ascii string to an integer in an arbitrary base.
      85             : **              Leading white space is ignored.  If 'base' is zero
      86             : **              it looks for a leading 0b, 0o or 0x to tell which
      87             : **              base.  If these are absent it defaults to 10.
      88             : **              Base must be 0 or between 2 and 36 (inclusive).
      89             : **              If 'ptr' is non-NULL it will contain a pointer to
      90             : **              the end of the scan.
      91             : **              Errors due to bad pointers will probably result in
      92             : **              exceptions - we don't check for them.
      93             : */
      94             : unsigned long
      95     5874740 : PyOS_strtoul(const char *str, char **ptr, int base)
      96             : {
      97     5874740 :     unsigned long result = 0; /* return value of the function */
      98             :     int c;             /* current input character */
      99             :     int ovlimit;       /* required digits to overflow */
     100             : 
     101             :     /* skip leading white space */
     102     5874740 :     while (*str && Py_ISSPACE(*str))
     103           0 :         ++str;
     104             : 
     105             :     /* check for leading 0b, 0o or 0x for auto-base or base 16 */
     106     5874740 :     switch (base) {
     107     5874740 :     case 0:             /* look for leading 0b, 0o or 0x */
     108     5874740 :         if (*str == '0') {
     109     1814730 :             ++str;
     110     1814730 :             if (*str == 'x' || *str == 'X') {
     111             :                 /* there must be at least one digit after 0x */
     112      194293 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
     113           0 :                     if (ptr)
     114           0 :                         *ptr = (char *)str;
     115           0 :                     return 0;
     116             :                 }
     117      194293 :                 ++str;
     118      194293 :                 base = 16;
     119     1620440 :             } else if (*str == 'o' || *str == 'O') {
     120             :                 /* there must be at least one digit after 0o */
     121        4863 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
     122           0 :                     if (ptr)
     123           0 :                         *ptr = (char *)str;
     124           0 :                     return 0;
     125             :                 }
     126        4863 :                 ++str;
     127        4863 :                 base = 8;
     128     1615580 :             } else if (*str == 'b' || *str == 'B') {
     129             :                 /* there must be at least one digit after 0b */
     130         742 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
     131           0 :                     if (ptr)
     132           0 :                         *ptr = (char *)str;
     133           0 :                     return 0;
     134             :                 }
     135         742 :                 ++str;
     136         742 :                 base = 2;
     137             :             } else {
     138             :                 /* skip all zeroes... */
     139     1615180 :                 while (*str == '0')
     140         344 :                     ++str;
     141     1614840 :                 while (Py_ISSPACE(*str))
     142           0 :                     ++str;
     143     1614840 :                 if (ptr)
     144     1614840 :                     *ptr = (char *)str;
     145     1614840 :                 return 0;
     146             :             }
     147             :         }
     148             :         else
     149     4060010 :             base = 10;
     150     4259910 :         break;
     151             : 
     152             :     /* even with explicit base, skip leading 0? prefix */
     153           0 :     case 16:
     154           0 :         if (*str == '0') {
     155           0 :             ++str;
     156           0 :             if (*str == 'x' || *str == 'X') {
     157             :                 /* there must be at least one digit after 0x */
     158           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
     159           0 :                     if (ptr)
     160           0 :                         *ptr = (char *)str;
     161           0 :                     return 0;
     162             :                 }
     163           0 :                 ++str;
     164             :             }
     165             :         }
     166           0 :         break;
     167           0 :     case 8:
     168           0 :         if (*str == '0') {
     169           0 :             ++str;
     170           0 :             if (*str == 'o' || *str == 'O') {
     171             :                 /* there must be at least one digit after 0o */
     172           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
     173           0 :                     if (ptr)
     174           0 :                         *ptr = (char *)str;
     175           0 :                     return 0;
     176             :                 }
     177           0 :                 ++str;
     178             :             }
     179             :         }
     180           0 :         break;
     181           0 :     case 2:
     182           0 :         if(*str == '0') {
     183           0 :             ++str;
     184           0 :             if (*str == 'b' || *str == 'B') {
     185             :                 /* there must be at least one digit after 0b */
     186           0 :                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
     187           0 :                     if (ptr)
     188           0 :                         *ptr = (char *)str;
     189           0 :                     return 0;
     190             :                 }
     191           0 :                 ++str;
     192             :             }
     193             :         }
     194           0 :         break;
     195             :     }
     196             : 
     197             :     /* catch silly bases */
     198     4259910 :     if (base < 2 || base > 36) {
     199           0 :         if (ptr)
     200           0 :             *ptr = (char *)str;
     201           0 :         return 0;
     202             :     }
     203             : 
     204             :     /* skip leading zeroes */
     205     4324870 :     while (*str == '0')
     206       64959 :         ++str;
     207             : 
     208             :     /* base is guaranteed to be in [2, 36] at this point */
     209     4259910 :     ovlimit = digitlimit[base];
     210             : 
     211             :     /* do the conversion until non-digit character encountered */
     212    14496500 :     while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
     213    10237300 :         if (ovlimit > 0) /* no overflow check required */
     214    10236200 :             result = result * base + c;
     215             :         else { /* requires overflow check */
     216             :             unsigned long temp_result;
     217             : 
     218        1057 :             if (ovlimit < 0) /* guaranteed overflow */
     219         183 :                 goto overflowed;
     220             : 
     221             :             /* there could be an overflow */
     222             :             /* check overflow just from shifting */
     223         874 :             if (result > smallmax[base])
     224         495 :                 goto overflowed;
     225             : 
     226         379 :             result *= base;
     227             : 
     228             :             /* check overflow from the digit's value */
     229         379 :             temp_result = result + c;
     230         379 :             if (temp_result < result)
     231          14 :                 goto overflowed;
     232             : 
     233         365 :             result = temp_result;
     234             :         }
     235             : 
     236    10236600 :         ++str;
     237    10236600 :         --ovlimit;
     238             :     }
     239             : 
     240             :     /* set pointer to point to the last character scanned */
     241     4259220 :     if (ptr)
     242     4259220 :         *ptr = (char *)str;
     243             : 
     244     4259220 :     return result;
     245             : 
     246         692 : overflowed:
     247         692 :     if (ptr) {
     248             :         /* spool through remaining digit characters */
     249       10236 :         while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
     250        9544 :             ++str;
     251         692 :         *ptr = (char *)str;
     252             :     }
     253         692 :     errno = ERANGE;
     254         692 :     return (unsigned long)-1;
     255             : }
     256             : 
     257             : /* Checking for overflow in PyOS_strtol is a PITA; see comments
     258             :  * about PY_ABS_LONG_MIN in longobject.c.
     259             :  */
     260             : #define PY_ABS_LONG_MIN         (0-(unsigned long)LONG_MIN)
     261             : 
     262             : long
     263     4060010 : PyOS_strtol(const char *str, char **ptr, int base)
     264             : {
     265             :     long result;
     266             :     unsigned long uresult;
     267             :     char sign;
     268             : 
     269     4060010 :     while (*str && Py_ISSPACE(*str))
     270           0 :         str++;
     271             : 
     272     4060010 :     sign = *str;
     273     4060010 :     if (sign == '+' || sign == '-')
     274           0 :         str++;
     275             : 
     276     4060010 :     uresult = PyOS_strtoul(str, ptr, base);
     277             : 
     278     4060010 :     if (uresult <= (unsigned long)LONG_MAX) {
     279     4059200 :         result = (long)uresult;
     280     4059200 :         if (sign == '-')
     281           0 :             result = -result;
     282             :     }
     283         812 :     else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
     284           0 :         result = LONG_MIN;
     285             :     }
     286             :     else {
     287         812 :         errno = ERANGE;
     288         812 :         result = LONG_MAX;
     289             :     }
     290     4060010 :     return result;
     291             : }

Generated by: LCOV version 1.14