diff options
author | sebres <sebres@users.sourceforge.net> | 2024-03-22 19:15:30 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2024-03-22 19:15:30 (GMT) |
commit | 37b65d597141873dd297aa86ec8e4c781380a2ca (patch) | |
tree | 0f23d6c5c1567d708fd1bf8e5c1f9d17a11fde17 /generic | |
parent | e3e7e3bb4bc2604fe7667d8dc2316c42e0766c8a (diff) | |
download | tcl-37b65d597141873dd297aa86ec8e4c781380a2ca.zip tcl-37b65d597141873dd297aa86ec8e4c781380a2ca.tar.gz tcl-37b65d597141873dd297aa86ec8e4c781380a2ca.tar.bz2 |
fix for [1f40aa83c552f597]: the overflow check could mistakenly pass in some cases (so basically expects div 10 to check it properly);
optimizes both str2int, since we don't need to check it for most cases at all, thus definitely faster now (O(n)+O(1) vs. O(n)+O(n) and also has fewer branch mispredictions).
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclClockFmt.c | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 9a32721..d36b4a8 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -56,6 +56,11 @@ static void ClockFrmScnFinalize(void *clientData); *---------------------------------------------------------------------- */ +/* int & Tcl_WideInt overflows may happens here (expected case) */ +#if defined(__GNUC__) || defined(__GNUG__) +# pragma GCC optimize("no-trapv") +#endif + static inline int _str2int( int *out, @@ -64,18 +69,29 @@ _str2int( int sign) { int val = 0, prev = 0; + const char *eNO = e; + /* overflow impossible for 10 digits ("9..9"), so no needs to check before */ + if (e-p > 10) { + eNO = p+10; + } if (sign >= 0) { - while (p < e) { + while (p < eNO) { /* never overflows */ val = val * 10 + (*p++ - '0'); - if (val < prev) { + } + while (p < e) { /* check for overflow */ + val = val * 10 + (*p++ - '0'); + if (val / 10 < prev) { return TCL_ERROR; } prev = val; } } else { - while (p < e) { + while (p < eNO) { /* never overflows */ + val = val * 10 - (*p++ - '0'); + } + while (p < e) { /* check for overflow */ val = val * 10 - (*p++ - '0'); - if (val > prev) { + if (val / 10 > prev) { return TCL_ERROR; } prev = val; @@ -85,11 +101,6 @@ _str2int( return TCL_OK; } -/* Tcl_WideInt overflows may happens here (expected case) */ -#if defined(__GNUC__) || defined(__GNUG__) -# pragma GCC optimize("no-trapv") -#endif - static inline int _str2wideInt( Tcl_WideInt *out, @@ -98,18 +109,29 @@ _str2wideInt( int sign) { Tcl_WideInt val = 0, prev = 0; + const char *eNO = e; + /* overflow impossible for 18 digits ("9..9"), so no needs to check before */ + if (e-p > 18) { + eNO = p+18; + } if (sign >= 0) { - while (p < e) { + while (p < eNO) { /* never overflows */ val = val * 10 + (*p++ - '0'); - if (val < prev) { + } + while (p < e) { /* check for overflow */ + val = val * 10 + (*p++ - '0'); + if (val / 10 < prev) { return TCL_ERROR; } prev = val; } } else { - while (p < e) { + while (p < eNO) { /* never overflows */ + val = val * 10 - (*p++ - '0'); + } + while (p < e) { /* check for overflow */ val = val * 10 - (*p++ - '0'); - if (val > prev) { + if (val / 10 > prev) { return TCL_ERROR; } prev = val; |