Commit | Line | Data |
---|---|---|
eba82382 VM |
1 | commit da1f431963218999c49cae928309dfec426c575c |
2 | Author: Joseph Myers <joseph@codesourcery.com> | |
3 | Date: Mon Aug 27 15:59:24 2012 +0000 | |
4 | ||
5 | Fix strtod integer/buffer overflow (bug 14459). | |
6 | (cherry picked from commit d6e70f4368533224e66d10b7f2126b899a3fd5e4) | |
7 | ||
8 | Conflicts: | |
9 | ||
10 | ChangeLog | |
11 | NEWS | |
12 | stdlib/Makefile | |
13 | ||
14 | diff --git a/stdlib/Makefile b/stdlib/Makefile | |
15 | index f7811c5..79c9acb 100644 | |
16 | --- a/stdlib/Makefile | |
17 | +++ b/stdlib/Makefile | |
18 | @@ -68,7 +68,8 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ | |
19 | tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \ | |
20 | tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \ | |
21 | tst-makecontext2 tst-strtod6 tst-unsetenv1 \ | |
22 | - tst-makecontext3 bug-getcontext bug-fmtmsg1 | |
23 | + tst-makecontext3 bug-getcontext bug-fmtmsg1 \ | |
24 | + tst-strtod-overflow | |
25 | ||
26 | include ../Makeconfig | |
27 | ||
28 | diff --git a/stdlib/strtod_l.c b/stdlib/strtod_l.c | |
29 | index 2166a08..a8a7ea8 100644 | |
30 | --- a/stdlib/strtod_l.c | |
31 | +++ b/stdlib/strtod_l.c | |
32 | @@ -60,6 +60,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, | |
33 | #include <math.h> | |
34 | #include <stdlib.h> | |
35 | #include <string.h> | |
36 | +#include <stdint.h> | |
37 | ||
38 | /* The gmp headers need some configuration frobs. */ | |
39 | #define HAVE_ALLOCA 1 | |
40 | @@ -72,7 +73,6 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **, | |
41 | #include "longlong.h" | |
42 | #include "fpioconst.h" | |
43 | ||
44 | -#define NDEBUG 1 | |
45 | #include <assert.h> | |
46 | ||
47 | ||
48 | @@ -174,19 +174,19 @@ extern const mp_limb_t _tens_in_limb[MAX_DIG_PER_LIMB + 1]; | |
49 | /* Return a floating point number of the needed type according to the given | |
50 | multi-precision number after possible rounding. */ | |
51 | static FLOAT | |
52 | -round_and_return (mp_limb_t *retval, int exponent, int negative, | |
53 | +round_and_return (mp_limb_t *retval, intmax_t exponent, int negative, | |
54 | mp_limb_t round_limb, mp_size_t round_bit, int more_bits) | |
55 | { | |
56 | if (exponent < MIN_EXP - 1) | |
57 | { | |
58 | - mp_size_t shift = MIN_EXP - 1 - exponent; | |
59 | - | |
60 | - if (shift > MANT_DIG) | |
61 | + if (exponent < MIN_EXP - 1 - MANT_DIG) | |
62 | { | |
63 | __set_errno (ERANGE); | |
64 | return 0.0; | |
65 | } | |
66 | ||
67 | + mp_size_t shift = MIN_EXP - 1 - exponent; | |
68 | + | |
69 | more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0; | |
70 | if (shift == MANT_DIG) | |
71 | /* This is a special case to handle the very seldom case where | |
72 | @@ -233,6 +233,9 @@ round_and_return (mp_limb_t *retval, int exponent, int negative, | |
73 | __set_errno (ERANGE); | |
74 | } | |
75 | ||
76 | + if (exponent > MAX_EXP) | |
77 | + goto overflow; | |
78 | + | |
79 | if ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0 | |
80 | && (more_bits || (retval[0] & 1) != 0 | |
81 | || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0)) | |
82 | @@ -258,6 +261,7 @@ round_and_return (mp_limb_t *retval, int exponent, int negative, | |
83 | } | |
84 | ||
85 | if (exponent > MAX_EXP) | |
86 | + overflow: | |
87 | return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; | |
88 | ||
89 | return MPN2FLOAT (retval, exponent, negative); | |
90 | @@ -271,7 +275,7 @@ round_and_return (mp_limb_t *retval, int exponent, int negative, | |
91 | factor for the resulting number (see code) multiply by it. */ | |
92 | static const STRING_TYPE * | |
93 | str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize, | |
94 | - int *exponent | |
95 | + intmax_t *exponent | |
96 | #ifndef USE_WIDE_CHAR | |
97 | , const char *decimal, size_t decimal_len, const char *thousands | |
98 | #endif | |
99 | @@ -301,6 +305,7 @@ str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize, | |
100 | cy += __mpn_add_1 (n, n, *nsize, low); | |
101 | if (cy != 0) | |
102 | { | |
103 | + assert (*nsize < MPNSIZE); | |
104 | n[*nsize] = cy; | |
105 | ++(*nsize); | |
106 | } | |
107 | @@ -335,7 +340,7 @@ str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize, | |
108 | } | |
109 | while (--digcnt > 0); | |
110 | ||
111 | - if (*exponent > 0 && cnt + *exponent <= MAX_DIG_PER_LIMB) | |
112 | + if (*exponent > 0 && *exponent <= MAX_DIG_PER_LIMB - cnt) | |
113 | { | |
114 | low *= _tens_in_limb[*exponent]; | |
115 | start = _tens_in_limb[cnt + *exponent]; | |
116 | @@ -355,7 +360,10 @@ str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize, | |
117 | cy = __mpn_mul_1 (n, n, *nsize, start); | |
118 | cy += __mpn_add_1 (n, n, *nsize, low); | |
119 | if (cy != 0) | |
120 | - n[(*nsize)++] = cy; | |
121 | + { | |
122 | + assert (*nsize < MPNSIZE); | |
123 | + n[(*nsize)++] = cy; | |
124 | + } | |
125 | } | |
126 | ||
127 | return str; | |
128 | @@ -413,7 +421,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
129 | { | |
130 | int negative; /* The sign of the number. */ | |
131 | MPN_VAR (num); /* MP representation of the number. */ | |
132 | - int exponent; /* Exponent of the number. */ | |
133 | + intmax_t exponent; /* Exponent of the number. */ | |
134 | ||
135 | /* Numbers starting `0X' or `0x' have to be processed with base 16. */ | |
136 | int base = 10; | |
137 | @@ -435,7 +443,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
138 | /* Points at the character following the integer and fractional digits. */ | |
139 | const STRING_TYPE *expp; | |
140 | /* Total number of digit and number of digits in integer part. */ | |
141 | - int dig_no, int_no, lead_zero; | |
142 | + size_t dig_no, int_no, lead_zero; | |
143 | /* Contains the last character read. */ | |
144 | CHAR_TYPE c; | |
145 | ||
146 | @@ -767,7 +775,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
147 | are all or any is really a fractional digit will be decided | |
148 | later. */ | |
149 | int_no = dig_no; | |
150 | - lead_zero = int_no == 0 ? -1 : 0; | |
151 | + lead_zero = int_no == 0 ? (size_t) -1 : 0; | |
152 | ||
153 | /* Read the fractional digits. A special case are the 'american | |
154 | style' numbers like `16.' i.e. with decimal point but without | |
155 | @@ -789,12 +797,13 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
156 | (base == 16 && ({ CHAR_TYPE lo = TOLOWER (c); | |
157 | lo >= L_('a') && lo <= L_('f'); }))) | |
158 | { | |
159 | - if (c != L_('0') && lead_zero == -1) | |
160 | + if (c != L_('0') && lead_zero == (size_t) -1) | |
161 | lead_zero = dig_no - int_no; | |
162 | ++dig_no; | |
163 | c = *++cp; | |
164 | } | |
165 | } | |
166 | + assert (dig_no <= (uintmax_t) INTMAX_MAX); | |
167 | ||
168 | /* Remember start of exponent (if any). */ | |
169 | expp = cp; | |
170 | @@ -817,24 +826,80 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
171 | ||
172 | if (c >= L_('0') && c <= L_('9')) | |
173 | { | |
174 | - int exp_limit; | |
175 | + intmax_t exp_limit; | |
176 | ||
177 | /* Get the exponent limit. */ | |
178 | if (base == 16) | |
179 | - exp_limit = (exp_negative ? | |
180 | - -MIN_EXP + MANT_DIG + 4 * int_no : | |
181 | - MAX_EXP - 4 * int_no + 4 * lead_zero + 3); | |
182 | + { | |
183 | + if (exp_negative) | |
184 | + { | |
185 | + assert (int_no <= (uintmax_t) (INTMAX_MAX | |
186 | + + MIN_EXP - MANT_DIG) / 4); | |
187 | + exp_limit = -MIN_EXP + MANT_DIG + 4 * (intmax_t) int_no; | |
188 | + } | |
189 | + else | |
190 | + { | |
191 | + if (int_no) | |
192 | + { | |
193 | + assert (lead_zero == 0 | |
194 | + && int_no <= (uintmax_t) INTMAX_MAX / 4); | |
195 | + exp_limit = MAX_EXP - 4 * (intmax_t) int_no + 3; | |
196 | + } | |
197 | + else if (lead_zero == (size_t) -1) | |
198 | + { | |
199 | + /* The number is zero and this limit is | |
200 | + arbitrary. */ | |
201 | + exp_limit = MAX_EXP + 3; | |
202 | + } | |
203 | + else | |
204 | + { | |
205 | + assert (lead_zero | |
206 | + <= (uintmax_t) (INTMAX_MAX - MAX_EXP - 3) / 4); | |
207 | + exp_limit = (MAX_EXP | |
208 | + + 4 * (intmax_t) lead_zero | |
209 | + + 3); | |
210 | + } | |
211 | + } | |
212 | + } | |
213 | else | |
214 | - exp_limit = (exp_negative ? | |
215 | - -MIN_10_EXP + MANT_DIG + int_no : | |
216 | - MAX_10_EXP - int_no + lead_zero + 1); | |
217 | + { | |
218 | + if (exp_negative) | |
219 | + { | |
220 | + assert (int_no | |
221 | + <= (uintmax_t) (INTMAX_MAX + MIN_10_EXP - MANT_DIG)); | |
222 | + exp_limit = -MIN_10_EXP + MANT_DIG + (intmax_t) int_no; | |
223 | + } | |
224 | + else | |
225 | + { | |
226 | + if (int_no) | |
227 | + { | |
228 | + assert (lead_zero == 0 | |
229 | + && int_no <= (uintmax_t) INTMAX_MAX); | |
230 | + exp_limit = MAX_10_EXP - (intmax_t) int_no + 1; | |
231 | + } | |
232 | + else if (lead_zero == (size_t) -1) | |
233 | + { | |
234 | + /* The number is zero and this limit is | |
235 | + arbitrary. */ | |
236 | + exp_limit = MAX_10_EXP + 1; | |
237 | + } | |
238 | + else | |
239 | + { | |
240 | + assert (lead_zero | |
241 | + <= (uintmax_t) (INTMAX_MAX - MAX_10_EXP - 1)); | |
242 | + exp_limit = MAX_10_EXP + (intmax_t) lead_zero + 1; | |
243 | + } | |
244 | + } | |
245 | + } | |
246 | + | |
247 | + if (exp_limit < 0) | |
248 | + exp_limit = 0; | |
249 | ||
250 | do | |
251 | { | |
252 | - exponent *= 10; | |
253 | - exponent += c - L_('0'); | |
254 | - | |
255 | - if (__builtin_expect (exponent > exp_limit, 0)) | |
256 | + if (__builtin_expect ((exponent > exp_limit / 10 | |
257 | + || (exponent == exp_limit / 10 | |
258 | + && c - L_('0') > exp_limit % 10)), 0)) | |
259 | /* The exponent is too large/small to represent a valid | |
260 | number. */ | |
261 | { | |
262 | @@ -843,7 +908,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
263 | /* We have to take care for special situation: a joker | |
264 | might have written "0.0e100000" which is in fact | |
265 | zero. */ | |
266 | - if (lead_zero == -1) | |
267 | + if (lead_zero == (size_t) -1) | |
268 | result = negative ? -0.0 : 0.0; | |
269 | else | |
270 | { | |
271 | @@ -862,6 +927,9 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
272 | /* NOTREACHED */ | |
273 | } | |
274 | ||
275 | + exponent *= 10; | |
276 | + exponent += c - L_('0'); | |
277 | + | |
278 | c = *++cp; | |
279 | } | |
280 | while (c >= L_('0') && c <= L_('9')); | |
281 | @@ -930,7 +998,14 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
282 | } | |
283 | #endif | |
284 | startp += lead_zero + decimal_len; | |
285 | - exponent -= base == 16 ? 4 * lead_zero : lead_zero; | |
286 | + assert (lead_zero <= (base == 16 | |
287 | + ? (uintmax_t) INTMAX_MAX / 4 | |
288 | + : (uintmax_t) INTMAX_MAX)); | |
289 | + assert (lead_zero <= (base == 16 | |
290 | + ? ((uintmax_t) exponent | |
291 | + - (uintmax_t) INTMAX_MIN) / 4 | |
292 | + : ((uintmax_t) exponent - (uintmax_t) INTMAX_MIN))); | |
293 | + exponent -= base == 16 ? 4 * (intmax_t) lead_zero : (intmax_t) lead_zero; | |
294 | dig_no -= lead_zero; | |
295 | } | |
296 | ||
297 | @@ -972,7 +1047,10 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
298 | } | |
299 | ||
300 | /* Adjust the exponent for the bits we are shifting in. */ | |
301 | - exponent += bits - 1 + (int_no - 1) * 4; | |
302 | + assert (int_no <= (uintmax_t) (exponent < 0 | |
303 | + ? (INTMAX_MAX - bits + 1) / 4 | |
304 | + : (INTMAX_MAX - exponent - bits + 1) / 4)); | |
305 | + exponent += bits - 1 + ((intmax_t) int_no - 1) * 4; | |
306 | ||
307 | while (--dig_no > 0 && idx >= 0) | |
308 | { | |
309 | @@ -1024,13 +1102,15 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
310 | really integer digits or belong to the fractional part; i.e. we normalize | |
311 | 123e-2 to 1.23. */ | |
312 | { | |
313 | - register int incr = (exponent < 0 ? MAX (-int_no, exponent) | |
314 | - : MIN (dig_no - int_no, exponent)); | |
315 | + register intmax_t incr = (exponent < 0 | |
316 | + ? MAX (-(intmax_t) int_no, exponent) | |
317 | + : MIN ((intmax_t) dig_no - (intmax_t) int_no, | |
318 | + exponent)); | |
319 | int_no += incr; | |
320 | exponent -= incr; | |
321 | } | |
322 | ||
323 | - if (__builtin_expect (int_no + exponent > MAX_10_EXP + 1, 0)) | |
324 | + if (__builtin_expect (exponent > MAX_10_EXP + 1 - (intmax_t) int_no, 0)) | |
325 | { | |
326 | __set_errno (ERANGE); | |
327 | return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL; | |
328 | @@ -1215,7 +1295,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
329 | digits we should have enough bits for the result. The remaining | |
330 | decimal digits give us the information that more bits are following. | |
331 | This can be used while rounding. (Two added as a safety margin.) */ | |
332 | - if (dig_no - int_no > (MANT_DIG - bits + 2) / 3 + 2) | |
333 | + if ((intmax_t) dig_no > (intmax_t) int_no + (MANT_DIG - bits + 2) / 3 + 2) | |
334 | { | |
335 | dig_no = int_no + (MANT_DIG - bits + 2) / 3 + 2; | |
336 | more_bits = 1; | |
337 | @@ -1223,7 +1303,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc) | |
338 | else | |
339 | more_bits = 0; | |
340 | ||
341 | - neg_exp = dig_no - int_no - exponent; | |
342 | + neg_exp = (intmax_t) dig_no - (intmax_t) int_no - exponent; | |
343 | ||
344 | /* Construct the denominator. */ | |
345 | densize = 0; | |
346 | diff --git a/stdlib/tst-strtod-overflow.c b/stdlib/tst-strtod-overflow.c | |
347 | new file mode 100644 | |
348 | index 0000000..668d55b | |
349 | --- /dev/null | |
350 | +++ b/stdlib/tst-strtod-overflow.c | |
351 | @@ -0,0 +1,48 @@ | |
352 | +/* Test for integer/buffer overflow in strtod. | |
353 | + Copyright (C) 2012 Free Software Foundation, Inc. | |
354 | + This file is part of the GNU C Library. | |
355 | + | |
356 | + The GNU C Library is free software; you can redistribute it and/or | |
357 | + modify it under the terms of the GNU Lesser General Public | |
358 | + License as published by the Free Software Foundation; either | |
359 | + version 2.1 of the License, or (at your option) any later version. | |
360 | + | |
361 | + The GNU C Library is distributed in the hope that it will be useful, | |
362 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
363 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
364 | + Lesser General Public License for more details. | |
365 | + | |
366 | + You should have received a copy of the GNU Lesser General Public | |
367 | + License along with the GNU C Library; if not, see | |
368 | + <http://www.gnu.org/licenses/>. */ | |
369 | + | |
370 | +#include <stdio.h> | |
371 | +#include <stdlib.h> | |
372 | +#include <string.h> | |
373 | + | |
374 | +#define EXPONENT "e-2147483649" | |
375 | +#define SIZE 214748364 | |
376 | + | |
377 | +static int | |
378 | +do_test (void) | |
379 | +{ | |
380 | + char *p = malloc (1 + SIZE + sizeof (EXPONENT)); | |
381 | + if (p == NULL) | |
382 | + { | |
383 | + puts ("malloc failed, cannot test for overflow"); | |
384 | + return 0; | |
385 | + } | |
386 | + p[0] = '1'; | |
387 | + memset (p + 1, '0', SIZE); | |
388 | + memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT)); | |
389 | + double d = strtod (p, NULL); | |
390 | + if (d != 0) | |
391 | + { | |
392 | + printf ("strtod returned wrong value: %a\n", d); | |
393 | + return 1; | |
394 | + } | |
395 | + return 0; | |
396 | +} | |
397 | + | |
398 | +#define TEST_FUNCTION do_test () | |
399 | +#include "../test-skeleton.c" |