summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2024-03-22 19:15:30 (GMT)
committersebres <sebres@users.sourceforge.net>2024-03-22 19:15:30 (GMT)
commit37b65d597141873dd297aa86ec8e4c781380a2ca (patch)
tree0f23d6c5c1567d708fd1bf8e5c1f9d17a11fde17 /generic
parente3e7e3bb4bc2604fe7667d8dc2316c42e0766c8a (diff)
downloadtcl-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.c48
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;