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