Skip to content

Commit f5a00d9

Browse files
committed
closes [tcl#96e5c814eb9ed955]: fixes sanitizer RTM-error signed integer overflow (no-trapv pragma also removed now), optimizing code, deduplication
1 parent 91e15ec commit f5a00d9

File tree

1 file changed

+85
-113
lines changed

1 file changed

+85
-113
lines changed

generic/tclClockFmt.c

Lines changed: 85 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -58,121 +58,112 @@ static void ClockFmtScnStorageDelete(ClockFmtScnStorage *fss);
5858
*----------------------------------------------------------------------
5959
*/
6060

61-
static inline void
62-
_str2int_no(
63-
int *out,
64-
register
65-
const char *p,
66-
const char *e,
67-
int sign)
68-
{
69-
/* assert(e <= p+10); */
70-
register int val = 0;
71-
/* overflow impossible for 10 digits ("9..9"), so no needs to check at all */
72-
while (p < e) { /* never overflows */
73-
val = val * 10 + (*p++ - '0');
74-
}
75-
if (sign < 0) { val = -val; }
76-
*out = val;
77-
}
78-
79-
static inline void
80-
_str2wideInt_no(
81-
Tcl_WideInt *out,
82-
register
83-
const char *p,
84-
const char *e,
85-
int sign)
86-
{
87-
/* assert(e <= p+18); */
88-
register Tcl_WideInt val = 0;
89-
/* overflow impossible for 18 digits ("9..9"), so no needs to check at all */
90-
while (p < e) { /* never overflows */
91-
val = val * 10 + (*p++ - '0');
92-
}
93-
if (sign < 0) { val = -val; }
94-
*out = val;
95-
}
96-
97-
/* int & Tcl_WideInt overflows may happens here (expected case) */
98-
#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__)
99-
# pragma GCC optimize("no-trapv")
100-
#endif
101-
10261
static inline int
10362
_str2int(
104-
int *out,
105-
register
63+
int *out,
10664
const char *p,
10765
const char *e,
10866
int sign)
10967
{
110-
register int val = 0;
111-
/* overflow impossible for 10 digits ("9..9"), so no needs to check before */
112-
const char *eNO = p+10;
113-
if (eNO > e) {
114-
eNO = e;
68+
char last;
69+
int val = 0;
70+
71+
if (e - p > 10) { /* definitely overflows */
72+
return TCL_ERROR;
11573
}
116-
while (p < eNO) { /* never overflows */
117-
val = val * 10 + (*p++ - '0');
74+
75+
/*
76+
* Overflow impossible for max 9 digits ("9..9"),
77+
* or for 10 digits if it starts with 1 ("19..9").
78+
*/
79+
if (e - p <= 9 || *p <= '1' ) {
80+
while (p < e) {
81+
val = val * 10 + (*p++ - '0');
82+
}
83+
*out = (sign >= 0) ? val : -val;
84+
return TCL_OK;
11885
}
86+
87+
/* 10 digits and it may overflow at last char */
88+
e--;
89+
while (p < e) {
90+
val = val * 10 + (*p++ - '0');
91+
}
92+
last = *p - '0';
11993
if (sign >= 0) {
120-
while (p < e) { /* check for overflow */
121-
int prev = val;
122-
val = val * 10 + (*p++ - '0');
123-
if (val / 10 < prev) {
124-
return TCL_ERROR;
125-
}
126-
}
94+
if ( (val > INT_MAX / 10)
95+
|| ((val == INT_MAX / 10) && (last > INT_MAX % 10))
96+
) {
97+
return TCL_ERROR; /* overflow*/
98+
}
99+
val = val * 10 + last;
127100
} else {
128-
val = -val;
129-
while (p < e) { /* check for overflow */
130-
int prev = val;
131-
val = val * 10 - (*p++ - '0');
132-
if (val / 10 > prev) {
133-
return TCL_ERROR;
134-
}
135-
}
101+
val = -val;
102+
if ( (val < INT_MIN / 10)
103+
|| ((val == INT_MIN / 10) && ((INT_MIN % 10 < 0) ?
104+
(last > -(INT_MIN % 10)) : (last > 10-(INT_MIN % 10))
105+
))
106+
) {
107+
return TCL_ERROR; /* overflow*/
108+
}
109+
val = val * 10 - last;
136110
}
111+
137112
*out = val;
138113
return TCL_OK;
139114
}
140115

141116
static inline int
142117
_str2wideInt(
143118
Tcl_WideInt *out,
144-
register
145-
const char *p,
146-
const char *e,
119+
const char *p,
120+
const char *e,
147121
int sign)
148122
{
149-
register Tcl_WideInt val = 0;
150-
/* overflow impossible for 18 digits ("9..9"), so no needs to check before */
151-
const char *eNO = p+18;
152-
if (eNO > e) {
153-
eNO = e;
123+
char last;
124+
Tcl_WideInt val = 0;
125+
126+
if (e - p > 19) { /* definitely overflows */
127+
return TCL_ERROR;
154128
}
155-
while (p < eNO) { /* never overflows */
156-
val = val * 10 + (*p++ - '0');
129+
130+
/*
131+
* Overflow impossible for max 18 digits ("9..9"),
132+
* or for 19 digits if it starts with 8 ("89..9").
133+
*/
134+
if (e - p <= 18 || *p <= '8' ) {
135+
while (p < e) {
136+
val = val * 10 + (*p++ - '0');
137+
}
138+
*out = (sign >= 0) ? val : -val;
139+
return TCL_OK;
140+
}
141+
142+
/* 19 digits and it may overflow at last char */
143+
e--;
144+
while (p < e) {
145+
val = val * 10 + (*p++ - '0');
157146
}
147+
last = *p - '0';
158148
if (sign >= 0) {
159-
while (p < e) { /* check for overflow */
160-
Tcl_WideInt prev = val;
161-
val = val * 10 + (*p++ - '0');
162-
if (val / 10 < prev) {
163-
return TCL_ERROR;
164-
}
165-
}
149+
if ( (val > WIDE_MAX / 10)
150+
|| ((val == WIDE_MAX / 10) && (last > WIDE_MAX % 10))
151+
) {
152+
return TCL_ERROR; /* overflow*/
153+
}
154+
val = val * 10 + last;
166155
} else {
167-
val = -val;
168-
while (p < e) { /* check for overflow */
169-
Tcl_WideInt prev = val;
170-
val = val * 10 - (*p++ - '0');
171-
if (val / 10 > prev) {
172-
return TCL_ERROR;
173-
}
174-
}
156+
val = -val;
157+
if ( (val < WIDE_MIN / 10)
158+
|| ((val == WIDE_MIN / 10) && ((WIDE_MIN % 10 < 0) ?
159+
(last > -(WIDE_MIN % 10)) : (last > 10-(WIDE_MIN % 10))
160+
))
161+
) {
162+
return TCL_ERROR; /* overflow*/
163+
}
164+
val = val * 10 - last;
175165
}
166+
176167
*out = val;
177168
return TCL_OK;
178169
}
@@ -186,10 +177,6 @@ TclAtoWIe(
186177
{
187178
return _str2wideInt(out, p, e, sign);
188179
}
189-
190-
#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__)
191-
# pragma GCC reset_options
192-
#endif
193180

194181
/*
195182
*----------------------------------------------------------------------
@@ -2398,30 +2385,15 @@ ClockScan(
23982385
if (map->offs) {
23992386
p = yyInput; x = p + size;
24002387
if (map->type == CTOKT_INT) {
2401-
if (size <= 10) {
2402-
_str2int_no((int *)(((char *)info) + map->offs),
2403-
p, x, sign);
2404-
} else {
2405-
/* we don't have such large scan tokens at the moment */
2406-
goto overflow;
2407-
/* currently unused (maxSize of CTOKT_INT tokens <= 10) */
2408-
#if 0
2409-
if (_str2int((int *)(((char *)info) + map->offs),
2388+
if (_str2int((int *)(((char *)info) + map->offs),
24102389
p, x, sign) != TCL_OK) {
2411-
goto overflow;
2412-
}
2413-
#endif
2390+
goto overflow;
24142391
}
24152392
p = x;
24162393
} else {
2417-
if (size <= 18) {
2418-
_str2wideInt_no((Tcl_WideInt *)(((char *)info) + map->offs),
2419-
p, x, sign);
2420-
} else {
2421-
if (_str2wideInt((Tcl_WideInt *)(((char *)info) + map->offs),
2394+
if (_str2wideInt((Tcl_WideInt *)(((char *)info) + map->offs),
24222395
p, x, sign) != TCL_OK) {
2423-
goto overflow;
2424-
}
2396+
goto overflow;
24252397
}
24262398
p = x;
24272399
}

0 commit comments

Comments
 (0)