diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index 9dd8ecb..188b9bf 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -56,7 +56,7 @@ static void ClockFrmScnFinalize(ClientData clientData); *---------------------------------------------------------------------- */ -/* int overflows may happens here (expected case) */ +/* int & Tcl_WideInt overflows may happens here (expected case) */ #if defined(__GNUC__) || defined(__GNUG__) # pragma GCC optimize("no-trapv") #endif @@ -69,22 +69,33 @@ _str2int( const char *e, int sign) { - register int val = 0, prev = 0; + register int val = 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'); + } + while (p < e) { /* check for overflow */ + int prev = val; val = val * 10 + (*p++ - '0'); - if (val < prev) { + 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 */ + int prev = val; val = val * 10 - (*p++ - '0'); - if (val > prev) { + if (val / 10 > prev) { return TCL_ERROR; } - prev = val; } } *out = val; @@ -99,22 +110,33 @@ _str2wideInt( const char *e, int sign) { - register Tcl_WideInt val = 0, prev = 0; + register Tcl_WideInt val = 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'); + } + while (p < e) { /* check for overflow */ + Tcl_WideInt prev = val; val = val * 10 + (*p++ - '0'); - if (val < prev) { + 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 */ + Tcl_WideInt prev = val; val = val * 10 - (*p++ - '0'); - if (val > prev) { + if (val / 10 > prev) { return TCL_ERROR; } - prev = val; } } *out = val; diff --git a/tests/clock.test b/tests/clock.test index 513ae94..9f65ac7 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -18685,13 +18685,36 @@ test clock-6.8 {input of seconds} { } 9223372036854775807 test clock-6.9 {input of seconds - overflow} { - list [catch {clock scan -9223372036854775809 -format %s -gmt true} result] $result $::errorCode + list [catch {clock scan -9223372036854775809 -format %s -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] } {1 {requested date too large to represent} {CLOCK dateTooLarge}} - test clock-6.10 {input of seconds - overflow} { - list [catch {clock scan 9223372036854775808 -format %s -gmt true} result] $result $::errorCode + list [catch {clock scan 9223372036854775808 -format %s -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] } {1 {requested date too large to represent} {CLOCK dateTooLarge}} +foreach sign {{} -} { + test clock-6.10a {input of seconds - overflow, bug [1f40aa83c5]} { + list [catch {clock scan ${sign}27670116110564327423 -format %s -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] + } {1 {requested date too large to represent} {CLOCK dateTooLarge}} + test clock-6.10b {input of seconds - overflow, bug [1f40aa83c5]} { + list [catch {clock scan ${sign}27670116110564327424 -format %s -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] + } {1 {requested date too large to represent} {CLOCK dateTooLarge}} + test clock-6.10c {input of seconds - no overflow, bug [1f40aa83c5]} { + list [catch {clock scan ${sign}[string repeat 9 18] -format %s -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] + } [list 0 ${sign}[string repeat 9 18] {}] + test clock-6.10d {input of seconds - overflow, bug [1f40aa83c5]} { + list [catch {clock scan ${sign}[string repeat 9 19] -format %s -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] + } {1 {requested date too large to represent} {CLOCK dateTooLarge}} + # both fololowing freescan test don't generate overflow error, + # since it is a free scan, thus the token is simply not recognized further in yacc lexer, + # therefore we get parse error (can be surely changed latter): + test clock-6.10e {input of seconds - overflow (but since freescan parse error, but not boom), bug [1f40aa83c5]} -body { + list [catch {clock scan ${sign}27670116110564327423 -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] + } -match glob -result {1 {unable to convert date-time string "*": syntax error *} {TCL VALUE DATE PARSE}} + test clock-6.10f {input of seconds - overflow (but since freescan parse error, but not boom), bug [1f40aa83c5]} -body { + list [catch {clock scan ${sign}27670116110564327424 -gmt true} result opt] $result [if {[dict exists $opt -errorcode]} {dict get $opt -errorcode}] + } -match glob -result {1 {unable to convert date-time string "*": syntax error *} {TCL VALUE DATE PARSE}} +}; unset sign + test clock-6.11 {input of seconds - two values} { clock scan {1 2} -format {%s %s} -gmt true } 2