xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (C) 2000-2016 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. |
| 3 | Contributed by Jakub Jelinek <jakub@redhat.com>, 2000. |
| 4 | |
| 5 | The GNU C Library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | The GNU C Library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with the GNU C Library; if not, see |
| 17 | <http://www.gnu.org/licenses/>. */ |
| 18 | |
| 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 ("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 < sizeof (int_tests) / sizeof (int_tests[0]); ++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 < sizeof (double_tests) / sizeof (double_tests[0]); ++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 < sizeof (double_tests2) / sizeof (double_tests2[0]); ++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" |