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
do_test(void)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 ("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 ("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 ("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 ("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 ("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 ("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 ("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 ("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 ("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 + 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 ("FAIL: bug16618: SSCANF did not read one input item.\n");
255 	result = 1;
256       }
257     if (i != 0)
258       {
259 	printf ("FAIL: bug16618: Value of `i` was not zero as expected.\n");
260 	result = 1;
261       }
262     free (s);
263     if (result != 1)
264       printf ("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