1 | /* Copyright (C) 2000-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <array_length.h> |
19 | #include <stdlib.h> |
20 | #include <stdio.h> |
21 | #include <locale.h> |
22 | |
23 | #ifndef CHAR |
24 | # define CHAR char |
25 | # define L(str) str |
26 | # define SSCANF sscanf |
27 | #endif |
28 | |
29 | const CHAR *str_double[] = |
30 | { |
31 | L("-.10000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01" ), |
32 | L("0.10000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01" ), |
33 | L("-1234567E0198765432E0912345678901987654321091234567890198765432109" ), |
34 | L("-0.1000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01" ) |
35 | }; |
36 | |
37 | const double val_double[] = |
38 | { |
39 | -.10000E+02, 0.20000E+02, 0.25000E+01, 0.40000E+01, 0.50000E+01, 0.12500E+01, |
40 | 0.10000E+02, 0.20000E+02, 0.25000E+01, 0.40000E+01, 0.50000E+01, 0.12500E+01, |
41 | -1234567E01, 98765432E09, 12345678901.0, 98765432109.0, 12345678901.0, |
42 | 98765432109.0, |
43 | -0.1000E+02, 0.20000E+02, 0.25000E+01, 0.40000E+01, 0.50000E+01, 0.12500E+01 |
44 | }; |
45 | |
46 | const CHAR *str_long[] = |
47 | { |
48 | L("-12345678987654321123456789987654321123456789987654321" ), |
49 | L("-12345678987654321123456789987654321123456789987654321" ), |
50 | L("-12,345,678987,654,321123,456,789987,654,321123,456,789987,654,321" ), |
51 | L("-12,345,678987,654,321123,456,789987,654,321123,456,789987,654,321" ) |
52 | }; |
53 | |
54 | const CHAR *fmt_long[] = |
55 | { |
56 | L("%9ld%9ld%9ld%9ld%9ld%9ld" ), |
57 | L("%I9ld%I9ld%I9ld%I9ld%I9ld%I9ld" ), |
58 | L("%'11ld%'11ld%'11ld%'11ld%'11ld%'11ld" ), |
59 | L("%I'11ld%I'11ld%I'11ld%I'11ld%I'11ld%I'11ld" ) |
60 | }; |
61 | |
62 | const long int val_long[] = |
63 | { |
64 | -12345678, 987654321, 123456789, 987654321, 123456789, 987654321 |
65 | }; |
66 | |
67 | struct test |
68 | { |
69 | const CHAR *str; |
70 | const CHAR *fmt; |
71 | int retval; |
72 | } int_tests[] = |
73 | { |
74 | { L("foo\n" ), L("foo\nbar" ), -1 }, |
75 | { L("foo\n" ), L("foo bar" ), -1 }, |
76 | { L("foo\n" ), L("foo %d" ), -1 }, |
77 | { L("foo\n" ), L("foo\n%d" ), -1 }, |
78 | { L("foon" ), L("foonbar" ), -1 }, |
79 | { L("foon" ), L("foon%d" ), -1 }, |
80 | { L("foo " ), L("foo bar" ), -1 }, |
81 | { L("foo " ), L("foo %d" ), -1 }, |
82 | { L("foo\t" ), L("foo\tbar" ), -1 }, |
83 | { L("foo\t" ), L("foo bar" ), -1 }, |
84 | { L("foo\t" ), L("foo %d" ), -1 }, |
85 | { L("foo\t" ), L("foo\t%d" ), -1 }, |
86 | { L("foo" ), L("foo" ), 0 }, |
87 | { L("foon" ), L("foo bar" ), 0 }, |
88 | { L("foon" ), L("foo %d" ), 0 }, |
89 | { L("foo " ), L("fooxbar" ), 0 }, |
90 | { L("foo " ), L("foox%d" ), 0 }, |
91 | { L("foo bar" ), L("foon" ), 0 }, |
92 | { L("foo bar" ), L("foo bar" ), 0 }, |
93 | { L("foo bar" ), L("foo %d" ), 0 }, |
94 | { L("foo bar" ), L("foon%d" ), 0 }, |
95 | { L("foo (nil)" ), L("foo %p" ), 1}, |
96 | { L("foo (nil)" ), L("foo %4p" ), 0}, |
97 | { L("foo " ), L("foo %n" ), 0 }, |
98 | { L("foo%bar1" ), L("foo%%bar%d" ), 1 }, |
99 | /* Some OSes skip whitespace here while others don't. */ |
100 | { L("foo \t %bar1" ), L("foo%%bar%d" ), 1 } |
101 | }; |
102 | |
103 | struct test double_tests[] = |
104 | { |
105 | { L("-1" ), L("%1g" ), 0 }, |
106 | { L("-.1" ), L("%2g" ), 0 }, |
107 | { L("-inf" ), L("%3g" ), 0 }, |
108 | { L("+0" ), L("%1g" ), }, |
109 | { L("-0x1p0" ), L("%2g" ), 1 }, |
110 | { L("-..1" ), L("%g" ), 0 }, |
111 | { L("-inf" ), L("%g" ), 1 } |
112 | }; |
113 | |
114 | struct test2 |
115 | { |
116 | const CHAR *str; |
117 | const CHAR *fmt; |
118 | int retval; |
119 | char residual; |
120 | } double_tests2[] = |
121 | { |
122 | { L("0e+0" ), L("%g%c" ), 1, 0 }, |
123 | { L("0xe+0" ), L("%g%c" ), 2, '+' }, |
124 | { L("0x.e+0" ), L("%g%c" ), 2, '+' }, |
125 | }; |
126 | |
127 | static int |
128 | do_test (void) |
129 | { |
130 | double d[6]; |
131 | long l[6]; |
132 | int i, j; |
133 | int tst_locale; |
134 | int result = 0; |
135 | |
136 | tst_locale = 1; |
137 | if (tst_locale) |
138 | if (setlocale (LC_ALL, "en_US.ISO-8859-1" ) == NULL) |
139 | { |
140 | puts (s: "Failed to set en_US locale, skipping locale related tests" ); |
141 | tst_locale = 0; |
142 | } |
143 | |
144 | for (i = 0; i < 4; ++i) |
145 | { |
146 | if (SSCANF (str_double[i], L("%11lf%11lf%11lf%11lf%11lf%11lf" ), |
147 | &d[0], &d[1], &d[2], &d[3], &d[4], &d[5]) != 6) |
148 | { |
149 | printf (format: "Double sscanf test %d wrong number of " |
150 | "assigned inputs\n" , i); |
151 | result = 1; |
152 | } |
153 | else |
154 | for (j = 0; j < 6; ++j) |
155 | if (d[j] != val_double[6 * i + j]) |
156 | { |
157 | printf (format: "Double sscanf test %d failed (%g instead of %g)\n" , |
158 | i, d[j], val_double[6 * i + j]); |
159 | result = 1; |
160 | break; |
161 | } |
162 | } |
163 | |
164 | for (i = 0; i < 4; ++i) |
165 | { |
166 | if (SSCANF (str_long[i], fmt_long[i], |
167 | &l[0], &l[1], &l[2], &l[3], &l[4], &l[5]) != 6) |
168 | { |
169 | printf (format: "Integer sscanf test %d wrong number of " |
170 | "assigned inputs\n" , i); |
171 | result = 1; |
172 | } |
173 | else |
174 | for (j = 0; j < 6; ++j) |
175 | if (l[j] != val_long[j]) |
176 | { |
177 | printf (format: "Integer sscanf test %d failed (%ld instead %ld)\n" , |
178 | i, l[j], val_long[j]); |
179 | result = 1; |
180 | break; |
181 | } |
182 | |
183 | if (! tst_locale) |
184 | break; |
185 | } |
186 | |
187 | for (i = 0; i < array_length (int_tests); ++i) |
188 | { |
189 | long dummy; |
190 | int ret; |
191 | |
192 | if ((ret = SSCANF (int_tests[i].str, int_tests[i].fmt, |
193 | &dummy)) != int_tests[i].retval) |
194 | { |
195 | printf (format: "int_tests[%d] returned %d != %d\n" , |
196 | i, ret, int_tests[i].retval); |
197 | result = 1; |
198 | } |
199 | } |
200 | |
201 | for (i = 0; i < array_length (double_tests); ++i) |
202 | { |
203 | double dummy; |
204 | int ret; |
205 | |
206 | if ((ret = SSCANF (double_tests[i].str, double_tests[i].fmt, |
207 | &dummy)) != double_tests[i].retval) |
208 | { |
209 | printf (format: "double_tests[%d] returned %d != %d\n" , |
210 | i, ret, double_tests[i].retval); |
211 | result = 1; |
212 | } |
213 | } |
214 | |
215 | for (i = 0; i < array_length (double_tests2); ++i) |
216 | { |
217 | double dummy; |
218 | int ret; |
219 | char c = 0; |
220 | |
221 | if ((ret = SSCANF (double_tests2[i].str, double_tests2[i].fmt, |
222 | &dummy, &c)) != double_tests2[i].retval) |
223 | { |
224 | printf (format: "double_tests2[%d] returned %d != %d\n" , |
225 | i, ret, double_tests2[i].retval); |
226 | result = 1; |
227 | } |
228 | else if (ret == 2 && c != double_tests2[i].residual) |
229 | { |
230 | printf (format: "double_tests2[%d] stopped at '%c' != '%c'\n" , |
231 | i, c, double_tests2[i].residual); |
232 | result = 1; |
233 | } |
234 | } |
235 | |
236 | /* BZ #16618 |
237 | The test will segfault during SSCANF if the buffer overflow |
238 | is not fixed. The size of `s` is such that it forces the use |
239 | of malloc internally and this triggers the incorrect computation. |
240 | Thus the value for SIZE is arbitrariy high enough that malloc |
241 | is used. */ |
242 | { |
243 | #define SIZE 131072 |
244 | CHAR *s = malloc (size: (SIZE + 1) * sizeof (*s)); |
245 | if (s == NULL) |
246 | abort (); |
247 | for (size_t i = 0; i < SIZE; i++) |
248 | s[i] = L('0'); |
249 | s[SIZE] = L('\0'); |
250 | int i = 42; |
251 | /* Scan multi-digit zero into `i`. */ |
252 | if (SSCANF (s, L("%d" ), &i) != 1) |
253 | { |
254 | printf (format: "FAIL: bug16618: SSCANF did not read one input item.\n" ); |
255 | result = 1; |
256 | } |
257 | if (i != 0) |
258 | { |
259 | printf (format: "FAIL: bug16618: Value of `i` was not zero as expected.\n" ); |
260 | result = 1; |
261 | } |
262 | free (ptr: s); |
263 | if (result != 1) |
264 | printf (format: "PASS: bug16618: Did not crash.\n" ); |
265 | #undef SIZE |
266 | } |
267 | |
268 | |
269 | return result; |
270 | } |
271 | |
272 | #define TEST_FUNCTION do_test () |
273 | #include "../test-skeleton.c" |
274 | |