1 /* Tests in the "basic" test case for the Expat test suite
2 __ __ _
3 ___\ \/ /_ __ __ _| |_
4 / _ \\ /| '_ \ / _` | __|
5 | __// \| |_) | (_| | |_
6 \___/_/\_\ .__/ \__,_|\__|
7 |_| XML parser
8
9 Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
10 Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
11 Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
12 Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
13 Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org>
14 Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
15 Copyright (c) 2017 Joe Orton <jorton@redhat.com>
16 Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
17 Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
18 Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
19 Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
20 Copyright (c) 2021 Donghee Na <donghee.na@python.org>
21 Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
22 Copyright (c) 2024-2026 Berkay Eren Ürün <berkay.ueruen@siemens.com>
23 Copyright (c) 2026 Francesco Bertolaccini
24 Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@gmail.com>
25 Copyright (c) 2026 Kartik Kenchi <netliomax25@gmail.com>
26 Copyright (c) 2026 Zeyou Liu <zeyouliu@tencent.com>
27 Copyright (c) 2026 Afonso Januário <afonso-januario@hotmail.com>
28 Copyright (c) 2026 Braian Plaku <braianplaku@gmail.com>
29 Licensed under the MIT license:
30
31 Permission is hereby granted, free of charge, to any person obtaining
32 a copy of this software and associated documentation files (the
33 "Software"), to deal in the Software without restriction, including
34 without limitation the rights to use, copy, modify, merge, publish,
35 distribute, sublicense, and/or sell copies of the Software, and to permit
36 persons to whom the Software is furnished to do so, subject to the
37 following conditions:
38
39 The above copyright notice and this permission notice shall be included
40 in all copies or substantial portions of the Software.
41
42 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
45 NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
46 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
47 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
48 USE OR OTHER DEALINGS IN THE SOFTWARE.
49
50 SPDX-License-Identifier: MIT
51 */
52
53 #if defined(NDEBUG)
54 # undef NDEBUG /* because test suite relies on assert(...) at the moment */
55 #endif
56
57 #include "expat_config.h"
58
59 #include <assert.h>
60 #include <limits.h> // ULONG_MAX
61 #include <stdbool.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <time.h>
65
66 #include "expat.h"
67 #include "internal.h"
68 #include "minicheck.h"
69 #include "structdata.h"
70 #include "common.h"
71 #include "dummy.h"
72 #include "handlers.h"
73 #include "siphash.h"
74 #include "basic_tests.h"
75
76 #define EXPAT_TESTS_ASAN 1
77
78 #if defined(__has_feature)
79 # if ! __has_feature(address_sanitizer)
80 # undef EXPAT_TESTS_ASAN
81 # define EXPAT_TESTS_ASAN 0
82 # endif
83 #endif
84
85 #if ULONG_MAX == 18446744073709551615u // 2^64-1
86 # define EXPAT_TESTS_64BIT 1
87 #else
88 # define EXPAT_TESTS_64BIT 0
89 #endif
90
91 static void
basic_setup(void)92 basic_setup(void) {
93 g_parser = XML_ParserCreate(NULL);
94 if (g_parser == NULL)
95 fail("Parser not created.");
96 }
97
98 /*
99 * Character & encoding tests.
100 */
101
START_TEST(test_nul_byte)102 START_TEST(test_nul_byte) {
103 char text[] = "<doc>\0</doc>";
104
105 /* test that a NUL byte (in US-ASCII data) is an error */
106 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
107 == XML_STATUS_OK)
108 fail("Parser did not report error on NUL-byte.");
109 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
110 xml_failure(g_parser);
111 }
112 END_TEST
113
START_TEST(test_u0000_char)114 START_TEST(test_u0000_char) {
115 /* test that a NUL byte (in US-ASCII data) is an error */
116 expect_failure("<doc>�</doc>", XML_ERROR_BAD_CHAR_REF,
117 "Parser did not report error on NUL-byte.");
118 }
119 END_TEST
120
START_TEST(test_siphash_self)121 START_TEST(test_siphash_self) {
122 if (! sip24_valid())
123 fail("SipHash self-test failed");
124 }
125 END_TEST
126
START_TEST(test_siphash_spec)127 START_TEST(test_siphash_spec) {
128 /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */
129 const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
130 "\x0a\x0b\x0c\x0d\x0e";
131 const size_t len = sizeof(message) - 1;
132 const uint64_t expected = SIP_ULL(0xa129ca61U, 0x49be45e5U);
133 struct siphash state;
134 struct sipkey key;
135
136 sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
137 "\x0a\x0b\x0c\x0d\x0e\x0f");
138 sip24_init(&state, &key);
139
140 /* Cover spread across calls */
141 sip24_update(&state, message, 4);
142 sip24_update(&state, message + 4, len - 4);
143
144 /* Cover null length */
145 sip24_update(&state, message, 0);
146
147 if (sip24_final(&state) != expected)
148 fail("sip24_final failed spec test\n");
149
150 /* Cover wrapper */
151 if (siphash24(message, len, &key) != expected)
152 fail("siphash24 failed spec test\n");
153 }
154 END_TEST
155
START_TEST(test_bom_utf8)156 START_TEST(test_bom_utf8) {
157 /* This test is really just making sure we don't core on a UTF-8 BOM. */
158 const char *text = "\357\273\277<e/>";
159
160 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
161 == XML_STATUS_ERROR)
162 xml_failure(g_parser);
163 }
164 END_TEST
165
START_TEST(test_bom_utf16_be)166 START_TEST(test_bom_utf16_be) {
167 char text[] = "\376\377\0<\0e\0/\0>";
168
169 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
170 == XML_STATUS_ERROR)
171 xml_failure(g_parser);
172 }
173 END_TEST
174
START_TEST(test_bom_utf16_le)175 START_TEST(test_bom_utf16_le) {
176 char text[] = "\377\376<\0e\0/\0>\0";
177
178 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
179 == XML_STATUS_ERROR)
180 xml_failure(g_parser);
181 }
182 END_TEST
183
START_TEST(test_nobom_utf16_le)184 START_TEST(test_nobom_utf16_le) {
185 char text[] = " \0<\0e\0/\0>\0";
186
187 if (g_chunkSize == 1) {
188 // TODO: with just the first byte, we can't tell the difference between
189 // UTF-16-LE and UTF-8. Avoid the failure for now.
190 return;
191 }
192
193 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
194 == XML_STATUS_ERROR)
195 xml_failure(g_parser);
196 }
197 END_TEST
198
START_TEST(test_hash_collision)199 START_TEST(test_hash_collision) {
200 /* For full coverage of the lookup routine, we need to ensure a
201 * hash collision even though we can only tell that we have one
202 * through breakpoint debugging or coverage statistics. The
203 * following will cause a hash collision on machines with a 64-bit
204 * long type; others will have to experiment. The full coverage
205 * tests invoked from qa.sh usually provide a hash collision, but
206 * not always. This is an attempt to provide insurance.
207 */
208 #define COLLIDING_HASH_SALT (unsigned long)SIP_ULL(0xffffffffU, 0xff99fc90U)
209 const char *text
210 = "<doc>\n"
211 "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
212 "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n"
213 "<b5></b5><b6></b6><b7></b7><b8></b8>\n"
214 "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n"
215 "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n"
216 "<d8>This triggers the table growth and collides with b2</d8>\n"
217 "</doc>\n";
218
219 xmlSetHashSalt(g_parser, COLLIDING_HASH_SALT);
220 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
221 == XML_STATUS_ERROR)
222 xml_failure(g_parser);
223 }
224 END_TEST
225 #undef COLLIDING_HASH_SALT
226
START_TEST(test_hash_salt_setter)227 START_TEST(test_hash_salt_setter) {
228 const uint8_t entropy[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
229 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
230 XML_Parser parser = XML_ParserCreate(NULL);
231
232 // NULL parser should be rejected
233 assert_true(XML_SetHashSalt16Bytes(NULL, entropy) == XML_FALSE);
234
235 // NULL entropy should be rejected
236 assert_true(XML_SetHashSalt16Bytes(parser, NULL) == XML_FALSE);
237
238 // Setting should be allowed more than once
239 assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE);
240 assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE);
241
242 // But not after parsing has started
243 assert_true(XML_Parse(parser, "", 0, XML_FALSE /* isFinal */)
244 == XML_STATUS_OK);
245 assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_FALSE);
246
247 XML_ParserFree(parser);
248 }
249 END_TEST
250
251 /* Regression test for SF bug #491986. */
START_TEST(test_danish_latin1)252 START_TEST(test_danish_latin1) {
253 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
254 "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
255 #ifdef XML_UNICODE
256 const XML_Char *expected
257 = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5");
258 #else
259 const XML_Char *expected
260 = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
261 #endif
262 run_character_check(text, expected);
263 }
264 END_TEST
265
266 /* Regression test for SF bug #514281. */
START_TEST(test_french_charref_hexidecimal)267 START_TEST(test_french_charref_hexidecimal) {
268 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
269 "<doc>éèàçêÈ</doc>";
270 #ifdef XML_UNICODE
271 const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
272 #else
273 const XML_Char *expected
274 = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
275 #endif
276 run_character_check(text, expected);
277 }
278 END_TEST
279
START_TEST(test_french_charref_decimal)280 START_TEST(test_french_charref_decimal) {
281 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
282 "<doc>éèàçêÈ</doc>";
283 #ifdef XML_UNICODE
284 const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
285 #else
286 const XML_Char *expected
287 = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
288 #endif
289 run_character_check(text, expected);
290 }
291 END_TEST
292
START_TEST(test_french_latin1)293 START_TEST(test_french_latin1) {
294 const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
295 "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
296 #ifdef XML_UNICODE
297 const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
298 #else
299 const XML_Char *expected
300 = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
301 #endif
302 run_character_check(text, expected);
303 }
304 END_TEST
305
START_TEST(test_french_utf8)306 START_TEST(test_french_utf8) {
307 const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
308 "<doc>\xC3\xA9</doc>";
309 #ifdef XML_UNICODE
310 const XML_Char *expected = XCS("\x00e9");
311 #else
312 const XML_Char *expected = XCS("\xC3\xA9");
313 #endif
314 run_character_check(text, expected);
315 }
316 END_TEST
317
318 /* Regression test for SF bug #600479.
319 XXX There should be a test that exercises all legal XML Unicode
320 characters as PCDATA and attribute value content, and XML Name
321 characters as part of element and attribute names.
322 */
START_TEST(test_utf8_false_rejection)323 START_TEST(test_utf8_false_rejection) {
324 const char *text = "<doc>\xEF\xBA\xBF</doc>";
325 #ifdef XML_UNICODE
326 const XML_Char *expected = XCS("\xfebf");
327 #else
328 const XML_Char *expected = XCS("\xEF\xBA\xBF");
329 #endif
330 run_character_check(text, expected);
331 }
332 END_TEST
333
334 /* Regression test for SF bug #477667.
335 This test assures that any 8-bit character followed by a 7-bit
336 character will not be mistakenly interpreted as a valid UTF-8
337 sequence.
338 */
START_TEST(test_illegal_utf8)339 START_TEST(test_illegal_utf8) {
340 char text[100];
341 int i;
342
343 for (i = 128; i <= 255; ++i) {
344 snprintf(text, sizeof(text), "<e>%ccd</e>", i);
345 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
346 == XML_STATUS_OK) {
347 snprintf(text, sizeof(text),
348 "expected token error for '%c' (ordinal %d) in UTF-8 text", i,
349 i);
350 fail(text);
351 } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
352 xml_failure(g_parser);
353 /* Reset the parser since we use the same parser repeatedly. */
354 XML_ParserReset(g_parser, NULL);
355 }
356 }
357 END_TEST
358
359 /* Examples, not masks: */
360 #define UTF8_LEAD_1 "\x7f" /* 0b01111111 */
361 #define UTF8_LEAD_2 "\xdf" /* 0b11011111 */
362 #define UTF8_LEAD_3 "\xef" /* 0b11101111 */
363 #define UTF8_LEAD_4 "\xf7" /* 0b11110111 */
364 #define UTF8_FOLLOW "\xbf" /* 0b10111111 */
365
START_TEST(test_utf8_auto_align)366 START_TEST(test_utf8_auto_align) {
367 struct TestCase {
368 ptrdiff_t expectedMovementInChars;
369 const char *input;
370 };
371
372 struct TestCase cases[] = {
373 {00, ""},
374
375 {00, UTF8_LEAD_1},
376
377 {-1, UTF8_LEAD_2},
378 {00, UTF8_LEAD_2 UTF8_FOLLOW},
379
380 {-1, UTF8_LEAD_3},
381 {-2, UTF8_LEAD_3 UTF8_FOLLOW},
382 {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
383
384 {-1, UTF8_LEAD_4},
385 {-2, UTF8_LEAD_4 UTF8_FOLLOW},
386 {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
387 {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
388 };
389
390 size_t i = 0;
391 bool success = true;
392 for (; i < sizeof(cases) / sizeof(*cases); i++) {
393 const char *fromLim = cases[i].input + strlen(cases[i].input);
394 const char *const fromLimInitially = fromLim;
395 ptrdiff_t actualMovementInChars;
396
397 _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim);
398
399 actualMovementInChars = (fromLim - fromLimInitially);
400 if (actualMovementInChars != cases[i].expectedMovementInChars) {
401 size_t j = 0;
402 success = false;
403 printf("[-] UTF-8 case %2u: Expected movement by %2d chars"
404 ", actually moved by %2d chars: \"",
405 (unsigned)(i + 1), (int)cases[i].expectedMovementInChars,
406 (int)actualMovementInChars);
407 for (; j < strlen(cases[i].input); j++) {
408 printf("\\x%02x", (unsigned char)cases[i].input[j]);
409 }
410 printf("\"\n");
411 }
412 }
413
414 if (! success) {
415 fail("UTF-8 auto-alignment is not bullet-proof\n");
416 }
417 }
418 END_TEST
419
START_TEST(test_utf16)420 START_TEST(test_utf16) {
421 /* <?xml version="1.0" encoding="UTF-16"?>
422 * <doc a='123'>some {A} text</doc>
423 *
424 * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A
425 */
426 char text[]
427 = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
428 "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
429 "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
430 "\000'\000?\000>\000\n"
431 "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>"
432 "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000"
433 "<\000/\000d\000o\000c\000>";
434 #ifdef XML_UNICODE
435 const XML_Char *expected = XCS("some \xff21 text");
436 #else
437 const XML_Char *expected = XCS("some \357\274\241 text");
438 #endif
439 CharData storage;
440
441 CharData_Init(&storage);
442 XML_SetUserData(g_parser, &storage);
443 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
444 if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
445 == XML_STATUS_ERROR)
446 xml_failure(g_parser);
447 CharData_CheckXMLChars(&storage, expected);
448 }
449 END_TEST
450
START_TEST(test_utf16_le_epilog_newline)451 START_TEST(test_utf16_le_epilog_newline) {
452 unsigned int first_chunk_bytes = 17;
453 char text[] = "\xFF\xFE" /* BOM */
454 "<\000e\000/\000>\000" /* document element */
455 "\r\000\n\000\r\000\n\000"; /* epilog */
456
457 if (first_chunk_bytes >= sizeof(text) - 1)
458 fail("bad value of first_chunk_bytes");
459 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)first_chunk_bytes, XML_FALSE)
460 == XML_STATUS_ERROR)
461 xml_failure(g_parser);
462 else {
463 enum XML_Status rc;
464 rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes,
465 (int)(sizeof(text) - first_chunk_bytes - 1),
466 XML_TRUE);
467 if (rc == XML_STATUS_ERROR)
468 xml_failure(g_parser);
469 }
470 }
471 END_TEST
472
473 /* Test that an outright lie in the encoding is faulted */
START_TEST(test_not_utf16)474 START_TEST(test_not_utf16) {
475 const char *text = "<?xml version='1.0' encoding='utf-16'?>"
476 "<doc>Hi</doc>";
477
478 /* Use a handler to provoke the appropriate code paths */
479 XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
480 expect_failure(text, XML_ERROR_INCORRECT_ENCODING,
481 "UTF-16 declared in UTF-8 not faulted");
482 }
483 END_TEST
484
485 /* Test that an unknown encoding is rejected */
START_TEST(test_bad_encoding)486 START_TEST(test_bad_encoding) {
487 const char *text = "<doc>Hi</doc>";
488
489 if (! XML_SetEncoding(g_parser, XCS("unknown-encoding")))
490 fail("XML_SetEncoding failed");
491 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
492 "Unknown encoding not faulted");
493 }
494 END_TEST
495
496 /* Regression test for SF bug #481609, #774028. */
START_TEST(test_latin1_umlauts)497 START_TEST(test_latin1_umlauts) {
498 const char *text
499 = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
500 "<e a='\xE4 \xF6 \xFC ä ö ü ä ö ü >'\n"
501 " >\xE4 \xF6 \xFC ä ö ü ä ö ü ></e>";
502 #ifdef XML_UNICODE
503 /* Expected results in UTF-16 */
504 const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ")
505 XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >");
506 #else
507 /* Expected results in UTF-8 */
508 const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ")
509 XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >");
510 #endif
511
512 run_character_check(text, expected);
513 XML_ParserReset(g_parser, NULL);
514 run_attribute_check(text, expected);
515 /* Repeat with a default handler */
516 XML_ParserReset(g_parser, NULL);
517 XML_SetDefaultHandler(g_parser, dummy_default_handler);
518 run_character_check(text, expected);
519 XML_ParserReset(g_parser, NULL);
520 XML_SetDefaultHandler(g_parser, dummy_default_handler);
521 run_attribute_check(text, expected);
522 }
523 END_TEST
524
525 /* Test that an element name with a 4-byte UTF-8 character is rejected */
START_TEST(test_long_utf8_character)526 START_TEST(test_long_utf8_character) {
527 const char *text
528 = "<?xml version='1.0' encoding='utf-8'?>\n"
529 /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */
530 "<do\xf0\x90\x80\x80/>";
531 expect_failure(text, XML_ERROR_INVALID_TOKEN,
532 "4-byte UTF-8 character in element name not faulted");
533 }
534 END_TEST
535
536 /* Test that a long latin-1 attribute (too long to convert in one go)
537 * is correctly converted
538 */
START_TEST(test_long_latin1_attribute)539 START_TEST(test_long_latin1_attribute) {
540 const char *text
541 = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
542 "<doc att='"
543 /* 64 characters per line */
544 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
545 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
546 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
547 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
548 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
549 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
550 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
551 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
552 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
553 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
554 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
555 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
556 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
557 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
558 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
559 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
560 /* Last character splits across a buffer boundary */
561 "\xe4'>\n</doc>";
562
563 const XML_Char *expected =
564 /* 64 characters per line */
565 /* clang-format off */
566 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
567 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
568 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
569 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
570 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
571 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
572 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
573 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
574 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
575 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
576 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
577 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
578 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
579 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
580 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
581 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO")
582 /* clang-format on */
583 #ifdef XML_UNICODE
584 XCS("\x00e4");
585 #else
586 XCS("\xc3\xa4");
587 #endif
588
589 run_attribute_check(text, expected);
590 }
591 END_TEST
592
593 /* Test that a long ASCII attribute (too long to convert in one go)
594 * is correctly converted
595 */
START_TEST(test_long_ascii_attribute)596 START_TEST(test_long_ascii_attribute) {
597 const char *text
598 = "<?xml version='1.0' encoding='us-ascii'?>\n"
599 "<doc att='"
600 /* 64 characters per line */
601 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
602 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
603 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
604 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
605 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
606 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
607 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
608 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
609 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
610 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
611 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
612 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
613 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
614 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
615 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
616 "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
617 "01234'>\n</doc>";
618 const XML_Char *expected =
619 /* 64 characters per line */
620 /* clang-format off */
621 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
622 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
623 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
624 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
625 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
626 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
627 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
628 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
629 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
630 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
631 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
632 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
633 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
634 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
635 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
636 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
637 XCS("01234");
638 /* clang-format on */
639
640 run_attribute_check(text, expected);
641 }
642 END_TEST
643
644 /* Regression test #1 for SF bug #653180. */
START_TEST(test_line_number_after_parse)645 START_TEST(test_line_number_after_parse) {
646 const char *text = "<tag>\n"
647 "\n"
648 "\n</tag>";
649 XML_Size lineno;
650
651 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
652 == XML_STATUS_ERROR)
653 xml_failure(g_parser);
654 lineno = XML_GetCurrentLineNumber(g_parser);
655 if (lineno != 4) {
656 char buffer[100];
657 snprintf(buffer, sizeof(buffer),
658 "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
659 fail(buffer);
660 }
661 }
662 END_TEST
663
664 /* Regression test #2 for SF bug #653180. */
START_TEST(test_column_number_after_parse)665 START_TEST(test_column_number_after_parse) {
666 const char *text = "<tag></tag>";
667 XML_Size colno;
668
669 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
670 == XML_STATUS_ERROR)
671 xml_failure(g_parser);
672 colno = XML_GetCurrentColumnNumber(g_parser);
673 if (colno != 11) {
674 char buffer[100];
675 snprintf(buffer, sizeof(buffer),
676 "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
677 fail(buffer);
678 }
679 }
680 END_TEST
681
682 /* Regression test #3 for SF bug #653180. */
START_TEST(test_line_and_column_numbers_inside_handlers)683 START_TEST(test_line_and_column_numbers_inside_handlers) {
684 const char *text = "<a>\n" /* Unix end-of-line */
685 " <b>\r\n" /* Windows end-of-line */
686 " <c/>\r" /* Mac OS end-of-line */
687 " </b>\n"
688 " <d>\n"
689 " <f/>\n"
690 " </d>\n"
691 "</a>";
692 const StructDataEntry expected[]
693 = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG},
694 {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG},
695 {XCS("b"), 2, 4, STRUCT_END_TAG}, {XCS("d"), 2, 5, STRUCT_START_TAG},
696 {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG},
697 {XCS("d"), 2, 7, STRUCT_END_TAG}, {XCS("a"), 0, 8, STRUCT_END_TAG}};
698 const int expected_count = sizeof(expected) / sizeof(StructDataEntry);
699 StructData storage;
700
701 StructData_Init(&storage);
702 XML_SetUserData(g_parser, &storage);
703 XML_SetStartElementHandler(g_parser, start_element_event_handler2);
704 XML_SetEndElementHandler(g_parser, end_element_event_handler2);
705 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
706 == XML_STATUS_ERROR)
707 xml_failure(g_parser);
708
709 StructData_CheckItems(&storage, expected, expected_count);
710 StructData_Dispose(&storage);
711 }
712 END_TEST
713
714 /* Regression test #4 for SF bug #653180. */
START_TEST(test_line_number_after_error)715 START_TEST(test_line_number_after_error) {
716 const char *text = "<a>\n"
717 " <b>\n"
718 " </a>"; /* missing </b> */
719 XML_Size lineno;
720 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
721 != XML_STATUS_ERROR)
722 fail("Expected a parse error");
723
724 lineno = XML_GetCurrentLineNumber(g_parser);
725 if (lineno != 3) {
726 char buffer[100];
727 snprintf(buffer, sizeof(buffer),
728 "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
729 fail(buffer);
730 }
731 }
732 END_TEST
733
734 /* Regression test #5 for SF bug #653180. */
START_TEST(test_column_number_after_error)735 START_TEST(test_column_number_after_error) {
736 const char *text = "<a>\n"
737 " <b>\n"
738 " </a>"; /* missing </b> */
739 XML_Size colno;
740 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
741 != XML_STATUS_ERROR)
742 fail("Expected a parse error");
743
744 colno = XML_GetCurrentColumnNumber(g_parser);
745 if (colno != 4) {
746 char buffer[100];
747 snprintf(buffer, sizeof(buffer),
748 "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
749 fail(buffer);
750 }
751 }
752 END_TEST
753
754 /* Regression test for SF bug #478332. */
START_TEST(test_really_long_lines)755 START_TEST(test_really_long_lines) {
756 /* This parses an input line longer than INIT_DATA_BUF_SIZE
757 characters long (defined to be 1024 in xmlparse.c). We take a
758 really cheesy approach to building the input buffer, because
759 this avoids writing bugs in buffer-filling code.
760 */
761 const char *text
762 = "<e>"
763 /* 64 chars */
764 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
765 /* until we have at least 1024 characters on the line: */
766 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
767 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
768 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
769 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
770 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
771 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
772 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
773 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
774 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
775 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
776 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
777 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
778 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
779 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
780 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
781 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
782 "</e>";
783 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
784 == XML_STATUS_ERROR)
785 xml_failure(g_parser);
786 }
787 END_TEST
788
789 /* Test cdata processing across a buffer boundary */
START_TEST(test_really_long_encoded_lines)790 START_TEST(test_really_long_encoded_lines) {
791 /* As above, except that we want to provoke an output buffer
792 * overflow with a non-trivial encoding. For this we need to pass
793 * the whole cdata in one go, not byte-by-byte.
794 */
795 void *buffer;
796 const char *text
797 = "<?xml version='1.0' encoding='iso-8859-1'?>"
798 "<e>"
799 /* 64 chars */
800 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
801 /* until we have at least 1024 characters on the line: */
802 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
803 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
804 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
805 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
806 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
807 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
808 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
809 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
810 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
811 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
812 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
813 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
814 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
815 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
816 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
817 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
818 "</e>";
819 int parse_len = (int)strlen(text);
820
821 /* Need a cdata handler to provoke the code path we want to test */
822 XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler);
823 buffer = XML_GetBuffer(g_parser, parse_len);
824 if (buffer == NULL)
825 fail("Could not allocate parse buffer");
826 assert(buffer != NULL);
827 memcpy(buffer, text, parse_len);
828 if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR)
829 xml_failure(g_parser);
830 }
831 END_TEST
832
833 /*
834 * Element event tests.
835 */
836
START_TEST(test_end_element_events)837 START_TEST(test_end_element_events) {
838 const char *text = "<a><b><c/></b><d><f/></d></a>";
839 const XML_Char *expected = XCS("/c/b/f/d/a");
840 CharData storage;
841
842 CharData_Init(&storage);
843 XML_SetUserData(g_parser, &storage);
844 XML_SetEndElementHandler(g_parser, end_element_event_handler);
845 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
846 == XML_STATUS_ERROR)
847 xml_failure(g_parser);
848 CharData_CheckXMLChars(&storage, expected);
849 }
850 END_TEST
851
852 /*
853 * Attribute tests.
854 */
855
856 /* Helper used by the following tests; this checks any "attr" and "refs"
857 attributes to make sure whitespace has been normalized.
858
859 Return true if whitespace has been normalized in a string, using
860 the rules for attribute value normalization. The 'is_cdata' flag
861 is needed since CDATA attributes don't need to have multiple
862 whitespace characters collapsed to a single space, while other
863 attribute data types do. (Section 3.3.3 of the recommendation.)
864 */
865 static int
is_whitespace_normalized(const XML_Char * s,int is_cdata)866 is_whitespace_normalized(const XML_Char *s, int is_cdata) {
867 int blanks = 0;
868 int at_start = 1;
869 while (*s) {
870 if (*s == XCS(' '))
871 ++blanks;
872 else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r'))
873 return 0;
874 else {
875 if (at_start) {
876 at_start = 0;
877 if (blanks && ! is_cdata)
878 /* illegal leading blanks */
879 return 0;
880 } else if (blanks > 1 && ! is_cdata)
881 return 0;
882 blanks = 0;
883 }
884 ++s;
885 }
886 if (blanks && ! is_cdata)
887 return 0;
888 return 1;
889 }
890
891 /* Check the attribute whitespace checker: */
START_TEST(test_helper_is_whitespace_normalized)892 START_TEST(test_helper_is_whitespace_normalized) {
893 assert(is_whitespace_normalized(XCS("abc"), 0));
894 assert(is_whitespace_normalized(XCS("abc"), 1));
895 assert(is_whitespace_normalized(XCS("abc def ghi"), 0));
896 assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
897 assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0));
898 assert(is_whitespace_normalized(XCS(" abc def ghi"), 1));
899 assert(! is_whitespace_normalized(XCS("abc def ghi"), 0));
900 assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
901 assert(! is_whitespace_normalized(XCS("abc def ghi "), 0));
902 assert(is_whitespace_normalized(XCS("abc def ghi "), 1));
903 assert(! is_whitespace_normalized(XCS(" "), 0));
904 assert(is_whitespace_normalized(XCS(" "), 1));
905 assert(! is_whitespace_normalized(XCS("\t"), 0));
906 assert(! is_whitespace_normalized(XCS("\t"), 1));
907 assert(! is_whitespace_normalized(XCS("\n"), 0));
908 assert(! is_whitespace_normalized(XCS("\n"), 1));
909 assert(! is_whitespace_normalized(XCS("\r"), 0));
910 assert(! is_whitespace_normalized(XCS("\r"), 1));
911 assert(! is_whitespace_normalized(XCS("abc\t def"), 1));
912 }
913 END_TEST
914
915 static void XMLCALL
check_attr_contains_normalized_whitespace(void * userData,const XML_Char * name,const XML_Char ** atts)916 check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
917 const XML_Char **atts) {
918 int i;
919 UNUSED_P(userData);
920 UNUSED_P(name);
921 for (i = 0; atts[i] != NULL; i += 2) {
922 const XML_Char *attrname = atts[i];
923 const XML_Char *value = atts[i + 1];
924 if (xcstrcmp(XCS("attr"), attrname) == 0
925 || xcstrcmp(XCS("ents"), attrname) == 0
926 || xcstrcmp(XCS("refs"), attrname) == 0) {
927 if (! is_whitespace_normalized(value, 0)) {
928 char buffer[256];
929 snprintf(buffer, sizeof(buffer),
930 "attribute value not normalized: %" XML_FMT_STR
931 "='%" XML_FMT_STR "'",
932 attrname, value);
933 fail(buffer);
934 }
935 }
936 }
937 }
938
START_TEST(test_attr_whitespace_normalization)939 START_TEST(test_attr_whitespace_normalization) {
940 const char *text
941 = "<!DOCTYPE doc [\n"
942 " <!ATTLIST doc\n"
943 " attr NMTOKENS #REQUIRED\n"
944 " ents ENTITIES #REQUIRED\n"
945 " refs IDREFS #REQUIRED>\n"
946 "]>\n"
947 "<doc attr=' a b c\t\td\te\t' refs=' id-1 \t id-2\t\t' \n"
948 " ents=' ent-1 \t\r\n"
949 " ent-2 ' >\n"
950 " <e id='id-1'/>\n"
951 " <e id='id-2'/>\n"
952 "</doc>";
953
954 XML_SetStartElementHandler(g_parser,
955 check_attr_contains_normalized_whitespace);
956 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
957 == XML_STATUS_ERROR)
958 xml_failure(g_parser);
959 }
960 END_TEST
961
962 /*
963 * XML declaration tests.
964 */
965
START_TEST(test_xmldecl_misplaced)966 START_TEST(test_xmldecl_misplaced) {
967 expect_failure("\n"
968 "<?xml version='1.0'?>\n"
969 "<a/>",
970 XML_ERROR_MISPLACED_XML_PI,
971 "failed to report misplaced XML declaration");
972 }
973 END_TEST
974
START_TEST(test_xmldecl_invalid)975 START_TEST(test_xmldecl_invalid) {
976 expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL,
977 "Failed to report invalid XML declaration");
978 }
979 END_TEST
980
START_TEST(test_xmldecl_missing_attr)981 START_TEST(test_xmldecl_missing_attr) {
982 expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL,
983 "Failed to report missing XML declaration attribute");
984 }
985 END_TEST
986
START_TEST(test_xmldecl_missing_value)987 START_TEST(test_xmldecl_missing_value) {
988 expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n"
989 "<doc/>",
990 XML_ERROR_XML_DECL,
991 "Failed to report missing attribute value");
992 }
993 END_TEST
994
START_TEST(test_xmldecl_empty_version)995 START_TEST(test_xmldecl_empty_version) {
996 expect_failure("<?xml version=''?>\n"
997 "<doc/>",
998 XML_ERROR_XML_DECL,
999 "Failed to report empty version in XML declaration");
1000 }
1001 END_TEST
1002
1003 /* Regression test for GH #967: Expat only implements XML 1.0 Fourth
1004 Edition, so a declared version outside the "1.x" family must be
1005 rejected rather than silently accepted. A version matching the Fifth
1006 Edition's VersionNum production ("1." followed by one or more digits)
1007 is accepted even though Expat itself only implements 1.0 Fourth
1008 Edition, per GH #967's review thread: rejecting "1.1" now would just
1009 have to be reverted once Expat tracks the Fifth Edition, so it's let
1010 through rather than blocked twice. */
START_TEST(test_xmldecl_wrong_version_number)1011 START_TEST(test_xmldecl_wrong_version_number) {
1012 const char *const badVersions[] = {"2.3", "0.9", "10", "1.", "1", " 1.0 "};
1013
1014 for (size_t i = 0; i < sizeof(badVersions) / sizeof(badVersions[0]); i++) {
1015 char doc[64];
1016 snprintf(doc, sizeof(doc), "<?xml version='%s'?>\n<doc/>", badVersions[i]);
1017 set_subtest("version='%s'", badVersions[i]);
1018
1019 XML_Parser parser = XML_ParserCreate(NULL);
1020 assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
1021 == XML_STATUS_ERROR);
1022 assert_true(XML_GetErrorCode(parser) == XML_ERROR_XML_DECL);
1023 XML_ParserFree(parser);
1024 }
1025 }
1026 END_TEST
1027
1028 /* GH #967's review pointed out that XML 1.0 Fifth Edition relaxed
1029 VersionNum to "1." followed by one or more digits, so versions like
1030 "1.1" and "1.123" should parse rather than being rejected. */
START_TEST(test_xmldecl_accepts_1_x_version)1031 START_TEST(test_xmldecl_accepts_1_x_version) {
1032 const char *const goodVersions[] = {"1.1", "1.123"};
1033
1034 for (size_t i = 0; i < sizeof(goodVersions) / sizeof(goodVersions[0]); i++) {
1035 char doc[64];
1036 snprintf(doc, sizeof(doc), "<?xml version='%s'?>\n<doc/>", goodVersions[i]);
1037 set_subtest("version='%s'", goodVersions[i]);
1038
1039 XML_Parser parser = XML_ParserCreate(NULL);
1040 assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
1041 == XML_STATUS_OK);
1042 XML_ParserFree(parser);
1043 }
1044 }
1045 END_TEST
1046
1047 /* Regression test for SF bug #584832. */
START_TEST(test_unknown_encoding_internal_entity)1048 START_TEST(test_unknown_encoding_internal_entity) {
1049 const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
1050 "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
1051 "<test a='&foo;'/>";
1052
1053 XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL);
1054 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1055 == XML_STATUS_ERROR)
1056 xml_failure(g_parser);
1057 }
1058 END_TEST
1059
1060 /* Test unrecognised encoding handler */
START_TEST(test_unrecognised_encoding_internal_entity)1061 START_TEST(test_unrecognised_encoding_internal_entity) {
1062 const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
1063 "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
1064 "<test a='&foo;'/>";
1065
1066 XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL);
1067 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1068 != XML_STATUS_ERROR)
1069 fail("Unrecognised encoding not rejected");
1070 }
1071 END_TEST
1072
1073 /* Regression test for SF bug #620106. */
START_TEST(test_ext_entity_set_encoding)1074 START_TEST(test_ext_entity_set_encoding) {
1075 const char *text = "<!DOCTYPE doc [\n"
1076 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1077 "]>\n"
1078 "<doc>&en;</doc>";
1079 ExtTest test_data
1080 = {/* This text says it's an unsupported encoding, but it's really
1081 UTF-8, which we tell Expat using XML_SetEncoding().
1082 */
1083 "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL};
1084 #ifdef XML_UNICODE
1085 const XML_Char *expected = XCS("\x00e9");
1086 #else
1087 const XML_Char *expected = XCS("\xc3\xa9");
1088 #endif
1089
1090 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1091 run_ext_character_check(text, &test_data, expected);
1092 }
1093 END_TEST
1094
1095 /* Test external entities with no handler */
START_TEST(test_ext_entity_no_handler)1096 START_TEST(test_ext_entity_no_handler) {
1097 const char *text = "<!DOCTYPE doc [\n"
1098 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1099 "]>\n"
1100 "<doc>&en;</doc>";
1101
1102 XML_SetDefaultHandler(g_parser, dummy_default_handler);
1103 run_character_check(text, XCS(""));
1104 }
1105 END_TEST
1106
1107 /* Test UTF-8 BOM is accepted */
START_TEST(test_ext_entity_set_bom)1108 START_TEST(test_ext_entity_set_bom) {
1109 const char *text = "<!DOCTYPE doc [\n"
1110 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1111 "]>\n"
1112 "<doc>&en;</doc>";
1113 ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */
1114 "<?xml encoding='iso-8859-3'?>"
1115 "\xC3\xA9",
1116 XCS("utf-8"), NULL};
1117 #ifdef XML_UNICODE
1118 const XML_Char *expected = XCS("\x00e9");
1119 #else
1120 const XML_Char *expected = XCS("\xc3\xa9");
1121 #endif
1122
1123 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1124 run_ext_character_check(text, &test_data, expected);
1125 }
1126 END_TEST
1127
1128 /* Test that bad encodings are faulted */
START_TEST(test_ext_entity_bad_encoding)1129 START_TEST(test_ext_entity_bad_encoding) {
1130 const char *text = "<!DOCTYPE doc [\n"
1131 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1132 "]>\n"
1133 "<doc>&en;</doc>";
1134 ExtFaults fault
1135 = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted",
1136 XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING};
1137
1138 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1139 XML_SetUserData(g_parser, &fault);
1140 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1141 "Bad encoding should not have been accepted");
1142 }
1143 END_TEST
1144
1145 /* Try handing an invalid encoding to an external entity parser */
START_TEST(test_ext_entity_bad_encoding_2)1146 START_TEST(test_ext_entity_bad_encoding_2) {
1147 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1148 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1149 "<doc>&entity;</doc>";
1150 ExtFaults fault
1151 = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted",
1152 XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING};
1153
1154 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1155 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1156 XML_SetUserData(g_parser, &fault);
1157 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1158 "Bad encoding not faulted in external entity handler");
1159 }
1160 END_TEST
1161
1162 /* Test that no error is reported for unknown entities if we don't
1163 read an external subset. This was fixed in Expat 1.95.5.
1164 */
START_TEST(test_wfc_undeclared_entity_unread_external_subset)1165 START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
1166 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
1167 "<doc>&entity;</doc>";
1168
1169 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1170 == XML_STATUS_ERROR)
1171 xml_failure(g_parser);
1172 }
1173 END_TEST
1174
1175 /* Test that an error is reported for unknown entities if we don't
1176 have an external subset.
1177 */
START_TEST(test_wfc_undeclared_entity_no_external_subset)1178 START_TEST(test_wfc_undeclared_entity_no_external_subset) {
1179 expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY,
1180 "Parser did not report undefined entity w/out a DTD.");
1181 }
1182 END_TEST
1183
1184 /* Test that an error is reported for unknown entities if we don't
1185 read an external subset, but have been declared standalone.
1186 */
START_TEST(test_wfc_undeclared_entity_standalone)1187 START_TEST(test_wfc_undeclared_entity_standalone) {
1188 const char *text
1189 = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1190 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1191 "<doc>&entity;</doc>";
1192
1193 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1194 "Parser did not report undefined entity (standalone).");
1195 }
1196 END_TEST
1197
1198 /* Test that an error is reported for unknown entities if we have read
1199 an external subset, and standalone is true.
1200 */
START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone)1201 START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
1202 const char *text
1203 = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1204 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1205 "<doc>&entity;</doc>";
1206 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1207
1208 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1209 XML_SetUserData(g_parser, &test_data);
1210 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1211 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1212 "Parser did not report undefined entity (external DTD).");
1213 }
1214 END_TEST
1215
1216 /* Test that external entity handling is not done if the parsing flag
1217 * is set to UNLESS_STANDALONE
1218 */
START_TEST(test_entity_with_external_subset_unless_standalone)1219 START_TEST(test_entity_with_external_subset_unless_standalone) {
1220 const char *text
1221 = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1222 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1223 "<doc>&entity;</doc>";
1224 ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL};
1225
1226 XML_SetParamEntityParsing(g_parser,
1227 XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
1228 XML_SetUserData(g_parser, &test_data);
1229 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1230 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1231 "Parser did not report undefined entity");
1232 }
1233 END_TEST
1234
1235 /* Test that no error is reported for unknown entities if we have read
1236 an external subset, and standalone is false.
1237 */
START_TEST(test_wfc_undeclared_entity_with_external_subset)1238 START_TEST(test_wfc_undeclared_entity_with_external_subset) {
1239 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1240 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1241 "<doc>&entity;</doc>";
1242 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1243
1244 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1245 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1246 run_ext_character_check(text, &test_data, XCS(""));
1247 }
1248 END_TEST
1249
1250 /* Test that an error is reported if our NotStandalone handler fails */
START_TEST(test_not_standalone_handler_reject)1251 START_TEST(test_not_standalone_handler_reject) {
1252 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1253 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1254 "<doc>&entity;</doc>";
1255 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1256
1257 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1258 XML_SetUserData(g_parser, &test_data);
1259 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1260 XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
1261 expect_failure(text, XML_ERROR_NOT_STANDALONE,
1262 "NotStandalone handler failed to reject");
1263
1264 /* Try again but without external entity handling */
1265 XML_ParserReset(g_parser, NULL);
1266 XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
1267 expect_failure(text, XML_ERROR_NOT_STANDALONE,
1268 "NotStandalone handler failed to reject");
1269 }
1270 END_TEST
1271
1272 /* Test that no error is reported if our NotStandalone handler succeeds */
START_TEST(test_not_standalone_handler_accept)1273 START_TEST(test_not_standalone_handler_accept) {
1274 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1275 "<!DOCTYPE doc SYSTEM 'foo'>\n"
1276 "<doc>&entity;</doc>";
1277 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1278
1279 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1280 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1281 XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
1282 run_ext_character_check(text, &test_data, XCS(""));
1283
1284 /* Repeat without the external entity handler */
1285 XML_ParserReset(g_parser, NULL);
1286 XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
1287 run_character_check(text, XCS(""));
1288 }
1289 END_TEST
1290
START_TEST(test_entity_start_tag_level_greater_than_one)1291 START_TEST(test_entity_start_tag_level_greater_than_one) {
1292 const char *const text = "<!DOCTYPE t1 [\n"
1293 " <!ENTITY e1 'hello'>\n"
1294 "]>\n"
1295 "<t1>\n"
1296 " <t2>&e1;</t2>\n"
1297 "</t1>\n";
1298
1299 XML_Parser parser = XML_ParserCreate(NULL);
1300 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text),
1301 /*isFinal*/ XML_TRUE)
1302 == XML_STATUS_OK);
1303 XML_ParserFree(parser);
1304 }
1305 END_TEST
1306
START_TEST(test_wfc_no_recursive_entity_refs)1307 START_TEST(test_wfc_no_recursive_entity_refs) {
1308 const char *text = "<!DOCTYPE doc [\n"
1309 " <!ENTITY entity '&entity;'>\n"
1310 "]>\n"
1311 "<doc>&entity;</doc>";
1312
1313 expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF,
1314 "Parser did not report recursive entity reference.");
1315 }
1316 END_TEST
1317
START_TEST(test_no_indirectly_recursive_entity_refs)1318 START_TEST(test_no_indirectly_recursive_entity_refs) {
1319 struct TestCase {
1320 const char *doc;
1321 bool usesParameterEntities;
1322 };
1323
1324 const struct TestCase cases[] = {
1325 // general entity + character data
1326 {"<!DOCTYPE a [\n"
1327 " <!ENTITY e1 '&e2;'>\n"
1328 " <!ENTITY e2 '&e1;'>\n"
1329 "]><a>&e2;</a>\n",
1330 false},
1331
1332 // general entity + attribute value
1333 {"<!DOCTYPE a [\n"
1334 " <!ENTITY e1 '&e2;'>\n"
1335 " <!ENTITY e2 '&e1;'>\n"
1336 "]><a k1='&e2;' />\n",
1337 false},
1338
1339 // parameter entity
1340 {"<!DOCTYPE doc [\n"
1341 " <!ENTITY % p1 '%p2;'>\n"
1342 " <!ENTITY % p2 '%p1;'>\n"
1343 " <!ENTITY % define_g \"<!ENTITY g '%p2;'>\">\n"
1344 " %define_g;\n"
1345 "]>\n"
1346 "<doc/>\n",
1347 true},
1348 };
1349 const XML_Bool reset_or_not[] = {XML_TRUE, XML_FALSE};
1350
1351 for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
1352 for (size_t j = 0; j < sizeof(reset_or_not) / sizeof(reset_or_not[0]);
1353 j++) {
1354 const XML_Bool reset_wanted = reset_or_not[j];
1355 const char *const doc = cases[i].doc;
1356 const bool usesParameterEntities = cases[i].usesParameterEntities;
1357
1358 set_subtest("[%i,reset=%i] %s", (int)i, (int)j, doc);
1359
1360 #ifdef XML_DTD // both GE and DTD
1361 const bool rejection_expected = true;
1362 #elif XML_GE == 1 // GE but not DTD
1363 const bool rejection_expected = ! usesParameterEntities;
1364 #else // neither DTD nor GE
1365 const bool rejection_expected = false;
1366 #endif
1367
1368 XML_Parser parser = XML_ParserCreate(NULL);
1369
1370 #ifdef XML_DTD
1371 if (usesParameterEntities) {
1372 assert_true(
1373 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)
1374 == 1);
1375 }
1376 #else
1377 UNUSED_P(usesParameterEntities);
1378 #endif // XML_DTD
1379
1380 const enum XML_Status status
1381 = _XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
1382 /*isFinal*/ XML_TRUE);
1383
1384 if (rejection_expected) {
1385 assert_true(status == XML_STATUS_ERROR);
1386 assert_true(XML_GetErrorCode(parser) == XML_ERROR_RECURSIVE_ENTITY_REF);
1387 } else {
1388 assert_true(status == XML_STATUS_OK);
1389 }
1390
1391 if (reset_wanted) {
1392 // This covers free'ing of (eventually) all three open entity lists by
1393 // XML_ParserReset.
1394 XML_ParserReset(parser, NULL);
1395 }
1396
1397 // This covers free'ing of (eventually) all three open entity lists by
1398 // XML_ParserFree (unless XML_ParserReset has already done that above).
1399 XML_ParserFree(parser);
1400 }
1401 }
1402 }
1403 END_TEST
1404
START_TEST(test_recursive_external_parameter_entity_2)1405 START_TEST(test_recursive_external_parameter_entity_2) {
1406 struct TestCase {
1407 const char *doc;
1408 enum XML_Status expectedStatus;
1409 };
1410
1411 struct TestCase cases[] = {
1412 {"<!ENTITY % p1 '%p1;'>", XML_STATUS_ERROR},
1413 {"<!ENTITY % p1 '%p1;'>"
1414 "<!ENTITY % p1 'first declaration wins'>",
1415 XML_STATUS_ERROR},
1416 {"<!ENTITY % p1 'first declaration wins'>"
1417 "<!ENTITY % p1 '%p1;'>",
1418 XML_STATUS_OK},
1419 {"<!ENTITY % p1 '%p1;'>", XML_STATUS_OK},
1420 };
1421
1422 for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
1423 const char *const doc = cases[i].doc;
1424 const enum XML_Status expectedStatus = cases[i].expectedStatus;
1425 set_subtest("%s", doc);
1426
1427 XML_Parser parser = XML_ParserCreate(NULL);
1428 assert_true(parser != NULL);
1429
1430 XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
1431 assert_true(ext_parser != NULL);
1432
1433 const enum XML_Status actualStatus
1434 = _XML_Parse_SINGLE_BYTES(ext_parser, doc, (int)strlen(doc), XML_TRUE);
1435
1436 assert_true(actualStatus == expectedStatus);
1437 if (actualStatus != XML_STATUS_OK) {
1438 assert_true(XML_GetErrorCode(ext_parser)
1439 == XML_ERROR_RECURSIVE_ENTITY_REF);
1440 }
1441
1442 XML_ParserFree(ext_parser);
1443 XML_ParserFree(parser);
1444 }
1445 }
1446 END_TEST
1447
1448 /* Test incomplete external entities are faulted */
START_TEST(test_ext_entity_invalid_parse)1449 START_TEST(test_ext_entity_invalid_parse) {
1450 const char *text = "<!DOCTYPE doc [\n"
1451 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1452 "]>\n"
1453 "<doc>&en;</doc>";
1454 const ExtFaults faults[]
1455 = {{"<", "Incomplete element declaration not faulted", NULL,
1456 XML_ERROR_UNCLOSED_TOKEN},
1457 {"<\xe2\x82", /* First two bytes of a three-byte char */
1458 "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
1459 {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL,
1460 XML_ERROR_PARTIAL_CHAR},
1461 {NULL, NULL, NULL, XML_ERROR_NONE}};
1462 const ExtFaults *fault = faults;
1463
1464 for (; fault->parse_text != NULL; fault++) {
1465 set_subtest("\"%s\"", fault->parse_text);
1466 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1467 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1468 XML_SetUserData(g_parser, (void *)fault);
1469 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1470 "Parser did not report external entity error");
1471 XML_ParserReset(g_parser, NULL);
1472 }
1473 }
1474 END_TEST
1475
1476 /* Regression test for SF bug #483514. */
START_TEST(test_dtd_default_handling)1477 START_TEST(test_dtd_default_handling) {
1478 const char *text = "<!DOCTYPE doc [\n"
1479 "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
1480 "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
1481 "<!ELEMENT doc EMPTY>\n"
1482 "<!ATTLIST doc a CDATA #IMPLIED>\n"
1483 "<?pi in dtd?>\n"
1484 "<!--comment in dtd-->\n"
1485 "]><doc/>";
1486
1487 XML_SetDefaultHandler(g_parser, accumulate_characters);
1488 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
1489 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
1490 XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
1491 XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
1492 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
1493 XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
1494 XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
1495 XML_SetCommentHandler(g_parser, dummy_comment_handler);
1496 XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
1497 XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
1498 run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>"));
1499 }
1500 END_TEST
1501
1502 /* Test handling of attribute declarations */
START_TEST(test_dtd_attr_handling)1503 START_TEST(test_dtd_attr_handling) {
1504 const char *prolog = "<!DOCTYPE doc [\n"
1505 "<!ELEMENT doc EMPTY>\n";
1506 AttTest attr_data[]
1507 = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n"
1508 "]>"
1509 "<doc a='two'/>",
1510 XCS("doc"), XCS("a"),
1511 XCS("(one|two|three)"), /* Extraneous spaces will be removed */
1512 NULL, XML_TRUE},
1513 {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n"
1514 "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n"
1515 "]>"
1516 "<doc/>",
1517 XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE},
1518 {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n"
1519 "]>"
1520 "<doc/>",
1521 XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE},
1522 {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n"
1523 "]>"
1524 "<doc/>",
1525 XCS("doc"), XCS("a"), XCS("CDATA"),
1526 #ifdef XML_UNICODE
1527 XCS("\x06f2"),
1528 #else
1529 XCS("\xdb\xb2"),
1530 #endif
1531 XML_FALSE},
1532 {NULL, NULL, NULL, NULL, NULL, XML_FALSE}};
1533 AttTest *test;
1534
1535 for (test = attr_data; test->definition != NULL; test++) {
1536 set_subtest("%s", test->definition);
1537 XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler);
1538 XML_SetUserData(g_parser, test);
1539 if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog),
1540 XML_FALSE)
1541 == XML_STATUS_ERROR)
1542 xml_failure(g_parser);
1543 if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition,
1544 (int)strlen(test->definition), XML_TRUE)
1545 == XML_STATUS_ERROR)
1546 xml_failure(g_parser);
1547 XML_ParserReset(g_parser, NULL);
1548 }
1549 }
1550 END_TEST
1551
1552 /* See related SF bug #673791.
1553 When namespace processing is enabled, setting the namespace URI for
1554 a prefix is not allowed; this test ensures that it *is* allowed
1555 when namespace processing is not enabled.
1556 (See Namespaces in XML, section 2.)
1557 */
START_TEST(test_empty_ns_without_namespaces)1558 START_TEST(test_empty_ns_without_namespaces) {
1559 const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
1560 " <e xmlns:prefix=''/>\n"
1561 "</doc>";
1562
1563 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1564 == XML_STATUS_ERROR)
1565 xml_failure(g_parser);
1566 }
1567 END_TEST
1568
1569 /* Regression test for SF bug #824420.
1570 Checks that an xmlns:prefix attribute set in an attribute's default
1571 value isn't misinterpreted.
1572 */
START_TEST(test_ns_in_attribute_default_without_namespaces)1573 START_TEST(test_ns_in_attribute_default_without_namespaces) {
1574 const char *text = "<!DOCTYPE e:element [\n"
1575 " <!ATTLIST e:element\n"
1576 " xmlns:e CDATA 'http://example.org/'>\n"
1577 " ]>\n"
1578 "<e:element/>";
1579
1580 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1581 == XML_STATUS_ERROR)
1582 xml_failure(g_parser);
1583 }
1584 END_TEST
1585
1586 /* Regression test for SF bug #1515266: missing check of stopped
1587 parser in doContext() 'for' loop. */
START_TEST(test_stop_parser_between_char_data_calls)1588 START_TEST(test_stop_parser_between_char_data_calls) {
1589 /* The sample data must be big enough that there are two calls to
1590 the character data handler from within the inner "for" loop of
1591 the XML_TOK_DATA_CHARS case in doContent(), and the character
1592 handler must stop the parser and clear the character data
1593 handler.
1594 */
1595 const char *text = long_character_data_text;
1596
1597 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
1598 g_resumable = XML_FALSE;
1599 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1600 != XML_STATUS_ERROR)
1601 xml_failure(g_parser);
1602 if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
1603 xml_failure(g_parser);
1604 }
1605 END_TEST
1606
1607 /* Regression test for SF bug #1515266: missing check of stopped
1608 parser in doContext() 'for' loop. */
START_TEST(test_suspend_parser_between_char_data_calls)1609 START_TEST(test_suspend_parser_between_char_data_calls) {
1610 /* The sample data must be big enough that there are two calls to
1611 the character data handler from within the inner "for" loop of
1612 the XML_TOK_DATA_CHARS case in doContent(), and the character
1613 handler must stop the parser and clear the character data
1614 handler.
1615 */
1616 const char *text = long_character_data_text;
1617
1618 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
1619 g_resumable = XML_TRUE;
1620 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
1621 // we won't know exactly how much input we actually managed to give Expat.
1622 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
1623 != XML_STATUS_SUSPENDED)
1624 xml_failure(g_parser);
1625 if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
1626 xml_failure(g_parser);
1627 /* Try parsing directly */
1628 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1629 != XML_STATUS_ERROR)
1630 fail("Attempt to continue parse while suspended not faulted");
1631 if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
1632 fail("Suspended parse not faulted with correct error");
1633 }
1634 END_TEST
1635
1636 /* Test repeated calls to XML_StopParser are handled correctly */
START_TEST(test_repeated_stop_parser_between_char_data_calls)1637 START_TEST(test_repeated_stop_parser_between_char_data_calls) {
1638 const char *text = long_character_data_text;
1639
1640 XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
1641 g_resumable = XML_FALSE;
1642 g_abortable = XML_FALSE;
1643 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1644 != XML_STATUS_ERROR)
1645 fail("Failed to double-stop parser");
1646
1647 XML_ParserReset(g_parser, NULL);
1648 XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
1649 g_resumable = XML_TRUE;
1650 g_abortable = XML_FALSE;
1651 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
1652 // we won't know exactly how much input we actually managed to give Expat.
1653 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
1654 != XML_STATUS_SUSPENDED)
1655 fail("Failed to double-suspend parser");
1656
1657 XML_ParserReset(g_parser, NULL);
1658 XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
1659 g_resumable = XML_TRUE;
1660 g_abortable = XML_TRUE;
1661 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1662 != XML_STATUS_ERROR)
1663 fail("Failed to suspend-abort parser");
1664 }
1665 END_TEST
1666
START_TEST(test_good_cdata_ascii)1667 START_TEST(test_good_cdata_ascii) {
1668 const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
1669 const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
1670
1671 CharData storage;
1672 CharData_Init(&storage);
1673 XML_SetUserData(g_parser, &storage);
1674 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
1675 /* Add start and end handlers for coverage */
1676 XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
1677 XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
1678
1679 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1680 == XML_STATUS_ERROR)
1681 xml_failure(g_parser);
1682 CharData_CheckXMLChars(&storage, expected);
1683
1684 /* Try again, this time with a default handler */
1685 XML_ParserReset(g_parser, NULL);
1686 CharData_Init(&storage);
1687 XML_SetUserData(g_parser, &storage);
1688 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
1689 XML_SetDefaultHandler(g_parser, dummy_default_handler);
1690
1691 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1692 == XML_STATUS_ERROR)
1693 xml_failure(g_parser);
1694 CharData_CheckXMLChars(&storage, expected);
1695 }
1696 END_TEST
1697
START_TEST(test_good_cdata_utf16)1698 START_TEST(test_good_cdata_utf16) {
1699 /* Test data is:
1700 * <?xml version='1.0' encoding='utf-16'?>
1701 * <a><![CDATA[hello]]></a>
1702 */
1703 const char text[]
1704 = "\0<\0?\0x\0m\0l\0"
1705 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
1706 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
1707 "1\0"
1708 "6\0'"
1709 "\0?\0>\0\n"
1710 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
1711 const XML_Char *expected = XCS("hello");
1712
1713 CharData storage;
1714 CharData_Init(&storage);
1715 XML_SetUserData(g_parser, &storage);
1716 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
1717
1718 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
1719 == XML_STATUS_ERROR)
1720 xml_failure(g_parser);
1721 CharData_CheckXMLChars(&storage, expected);
1722 }
1723 END_TEST
1724
START_TEST(test_good_cdata_utf16_le)1725 START_TEST(test_good_cdata_utf16_le) {
1726 /* Test data is:
1727 * <?xml version='1.0' encoding='utf-16'?>
1728 * <a><![CDATA[hello]]></a>
1729 */
1730 const char text[]
1731 = "<\0?\0x\0m\0l\0"
1732 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
1733 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
1734 "1\0"
1735 "6\0'"
1736 "\0?\0>\0\n"
1737 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>\0";
1738 const XML_Char *expected = XCS("hello");
1739
1740 CharData storage;
1741 CharData_Init(&storage);
1742 XML_SetUserData(g_parser, &storage);
1743 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
1744
1745 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
1746 == XML_STATUS_ERROR)
1747 xml_failure(g_parser);
1748 CharData_CheckXMLChars(&storage, expected);
1749 }
1750 END_TEST
1751
1752 /* Test UTF16 conversion of a long cdata string */
1753
1754 /* 16 characters: handy macro to reduce visual clutter */
1755 #define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"
1756
START_TEST(test_long_cdata_utf16)1757 START_TEST(test_long_cdata_utf16) {
1758 /* Test data is:
1759 * <?xlm version='1.0' encoding='utf-16'?>
1760 * <a><![CDATA[
1761 * ABCDEFGHIJKLMNOP
1762 * ]]></a>
1763 */
1764 const char text[]
1765 = "\0<\0?\0x\0m\0l\0 "
1766 "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 "
1767 "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>"
1768 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
1769 /* 64 characters per line */
1770 /* clang-format off */
1771 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1772 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1773 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1774 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1775 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1776 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1777 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1778 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1779 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1780 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1781 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1782 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1783 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1784 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1785 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1786 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
1787 A_TO_P_IN_UTF16
1788 /* clang-format on */
1789 "\0]\0]\0>\0<\0/\0a\0>";
1790 const XML_Char *expected =
1791 /* clang-format off */
1792 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1793 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1794 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1795 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1796 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1797 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1798 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1799 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1800 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1801 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1802 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1803 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1804 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1805 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1806 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1807 XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
1808 XCS("ABCDEFGHIJKLMNOP");
1809 /* clang-format on */
1810 CharData storage;
1811 void *buffer;
1812
1813 CharData_Init(&storage);
1814 XML_SetUserData(g_parser, &storage);
1815 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
1816 buffer = XML_GetBuffer(g_parser, sizeof(text) - 1);
1817 if (buffer == NULL)
1818 fail("Could not allocate parse buffer");
1819 assert(buffer != NULL);
1820 memcpy(buffer, text, sizeof(text) - 1);
1821 if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
1822 xml_failure(g_parser);
1823 CharData_CheckXMLChars(&storage, expected);
1824 }
1825 END_TEST
1826
1827 /* Test handling of multiple unit UTF-16 characters */
START_TEST(test_multichar_cdata_utf16)1828 START_TEST(test_multichar_cdata_utf16) {
1829 /* Test data is:
1830 * <?xml version='1.0' encoding='utf-16'?>
1831 * <a><![CDATA[{MINIM}{CROTCHET}]]></a>
1832 *
1833 * where {MINIM} is U+1d15e (a minim or half-note)
1834 * UTF-16: 0xd834 0xdd5e
1835 * UTF-8: 0xf0 0x9d 0x85 0x9e
1836 * and {CROTCHET} is U+1d15f (a crotchet or quarter-note)
1837 * UTF-16: 0xd834 0xdd5f
1838 * UTF-8: 0xf0 0x9d 0x85 0x9f
1839 */
1840 const char text[] = "\0<\0?\0x\0m\0l\0"
1841 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
1842 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
1843 "1\0"
1844 "6\0'"
1845 "\0?\0>\0\n"
1846 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
1847 "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f"
1848 "\0]\0]\0>\0<\0/\0a\0>";
1849 #ifdef XML_UNICODE
1850 const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f");
1851 #else
1852 const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f");
1853 #endif
1854 CharData storage;
1855
1856 CharData_Init(&storage);
1857 XML_SetUserData(g_parser, &storage);
1858 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
1859
1860 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
1861 == XML_STATUS_ERROR)
1862 xml_failure(g_parser);
1863 CharData_CheckXMLChars(&storage, expected);
1864 }
1865 END_TEST
1866
1867 /* Test that an element name with a UTF-16 surrogate pair is rejected */
START_TEST(test_utf16_bad_surrogate_pair)1868 START_TEST(test_utf16_bad_surrogate_pair) {
1869 /* Test data is:
1870 * <?xml version='1.0' encoding='utf-16'?>
1871 * <a><![CDATA[{BADLINB}]]></a>
1872 *
1873 * where {BADLINB} is U+10000 (the first Linear B character)
1874 * with the UTF-16 surrogate pair in the wrong order, i.e.
1875 * 0xdc00 0xd800
1876 */
1877 const char text[] = "\0<\0?\0x\0m\0l\0"
1878 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
1879 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
1880 "1\0"
1881 "6\0'"
1882 "\0?\0>\0\n"
1883 "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
1884 "\xdc\x00\xd8\x00"
1885 "\0]\0]\0>\0<\0/\0a\0>";
1886
1887 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
1888 != XML_STATUS_ERROR)
1889 fail("Reversed UTF-16 surrogate pair not faulted");
1890 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
1891 xml_failure(g_parser);
1892 }
1893 END_TEST
1894
1895 // Helper that creates a UTF-16LE copy of UTF-16BE literal input and vice versa
1896 static char *
utf16_dup_flipped(const char * text,size_t lenBytes)1897 utf16_dup_flipped(const char *text, size_t lenBytes) {
1898 assert_true(lenBytes < SIZE_MAX);
1899 assert_true(lenBytes % 2 == 0);
1900 char *const buffer = malloc(lenBytes + 1);
1901 assert_true(buffer != NULL);
1902
1903 for (size_t i = 0; i < lenBytes; i++) {
1904 // This maps 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, 4 -> 5, ..
1905 size_t j = i + ((i % 2 == 0) ? +1 : -1);
1906 assert_true(j < lenBytes);
1907 buffer[j] = text[i];
1908 }
1909
1910 buffer[lenBytes] = '\0';
1911
1912 return buffer;
1913 }
1914
1915 /* Tests that invalid combinations of surrogates are detected when decoding
1916 UTF-16, both little-endian and big-endian.
1917 Previously, a high surrogate not followed by a low surrogate slipped
1918 through. Without validation the high would consume the next
1919 code unit as a fake low, hiding e.g. a following '<' from the
1920 tokenizer. */
START_TEST(test_utf16_surrogate_pairs)1921 START_TEST(test_utf16_surrogate_pairs) {
1922 struct TestCase {
1923 const char *idea;
1924 const char *content;
1925 bool expectedSuccess;
1926 };
1927
1928 struct TestCase testCases[] = {
1929 // Group {smallest high - 1}{*}
1930 {"{smallest high - 1}{smallest high - 1}",
1931 "\0<\0a\0>"
1932 "\xD7\xFF"
1933 "\xD7\xFF"
1934 "\0<\0/\0a\0>",
1935 true},
1936 {"{smallest high - 1}{smallest high}",
1937 "\0<\0a\0>"
1938 "\xD7\xFF"
1939 "\xD8\x00"
1940 "\0<\0/\0a\0>",
1941 false},
1942 {"{smallest high - 1}{largest high}",
1943 "\0<\0a\0>"
1944 "\xD7\xFF"
1945 "\xDB\xFF"
1946 "\0<\0/\0a\0>",
1947 false},
1948 {"{smallest high - 1}{smallest low}",
1949 "\0<\0a\0>"
1950 "\xD7\xFF"
1951 "\xDC\x00"
1952 "\0<\0/\0a\0>",
1953 false},
1954 {"{smallest high - 1}{largest low}",
1955 "\0<\0a\0>"
1956 "\xD7\xFF"
1957 "\xDF\xFF"
1958 "\0<\0/\0a\0>",
1959 false},
1960 {"{smallest high - 1}{largest low + 1}",
1961 "\0<\0a\0>"
1962 "\xD7\xFF"
1963 "\xE0\x00"
1964 "\0<\0/\0a\0>",
1965 true},
1966 // Group {smallest high}{*}
1967 {"{smallest high}{smallest high - 1}",
1968 "\0<\0a\0>"
1969 "\xD8\x00"
1970 "\xD7\xFF"
1971 "\0<\0/\0a\0>",
1972 false},
1973 {"{smallest high}{smallest high}",
1974 "\0<\0a\0>"
1975 "\xD8\x00"
1976 "\xD8\x00"
1977 "\0<\0/\0a\0>",
1978 false},
1979 {"{smallest high}{largest high}",
1980 "\0<\0a\0>"
1981 "\xD8\x00"
1982 "\xDB\xFF"
1983 "\0<\0/\0a\0>",
1984 false},
1985 {"{smallest high}{smallest low}",
1986 "\0<\0a\0>"
1987 "\xD8\x00"
1988 "\xDC\x00"
1989 "\0<\0/\0a\0>",
1990 true},
1991 {"{smallest high}{largest low}",
1992 "\0<\0a\0>"
1993 "\xD8\x00"
1994 "\xDF\xFF"
1995 "\0<\0/\0a\0>",
1996 true},
1997 {"{smallest high}{largest low + 1}",
1998 "\0<\0a\0>"
1999 "\xD8\x00"
2000 "\xE0\x00"
2001 "\0<\0/\0a\0>",
2002 false},
2003 // Group {largest high}{*}
2004 {"{largest high}{smallest high - 1}",
2005 "\0<\0a\0>"
2006 "\xDB\xFF"
2007 "\xD7\xFF"
2008 "\0<\0/\0a\0>",
2009 false},
2010 {"{largest high}{smallest high}",
2011 "\0<\0a\0>"
2012 "\xDB\xFF"
2013 "\xD8\x00"
2014 "\0<\0/\0a\0>",
2015 false},
2016 {"{largest high}{largest high}",
2017 "\0<\0a\0>"
2018 "\xDB\xFF"
2019 "\xDB\xFF"
2020 "\0<\0/\0a\0>",
2021 false},
2022 {"{largest high}{smallest low}",
2023 "\0<\0a\0>"
2024 "\xDB\xFF"
2025 "\xDC\x00"
2026 "\0<\0/\0a\0>",
2027 true},
2028 {"{largest high}{largest low}",
2029 "\0<\0a\0>"
2030 "\xDB\xFF"
2031 "\xDF\xFF"
2032 "\0<\0/\0a\0>",
2033 true},
2034 {"{largest high}{largest low + 1}",
2035 "\0<\0a\0>"
2036 "\xDB\xFF"
2037 "\xE0\x00"
2038 "\0<\0/\0a\0>",
2039 false},
2040 // Group {smallest low}{*}
2041 {"{smallest low}{smallest high - 1}",
2042 "\0<\0a\0>"
2043 "\xDC\x00"
2044 "\xD7\xFF"
2045 "\0<\0/\0a\0>",
2046 false},
2047 {"{smallest low}{smallest high}",
2048 "\0<\0a\0>"
2049 "\xDC\x00"
2050 "\xD8\x00"
2051 "\0<\0/\0a\0>",
2052 false},
2053 {"{smallest low}{largest high}",
2054 "\0<\0a\0>"
2055 "\xDC\x00"
2056 "\xDB\xFF"
2057 "\0<\0/\0a\0>",
2058 false},
2059 {"{smallest low}{smallest low}",
2060 "\0<\0a\0>"
2061 "\xDC\x00"
2062 "\xDC\x00"
2063 "\0<\0/\0a\0>",
2064 false},
2065 {"{smallest low}{largest low}",
2066 "\0<\0a\0>"
2067 "\xDC\x00"
2068 "\xDF\xFF"
2069 "\0<\0/\0a\0>",
2070 false},
2071 {"{smallest low}{largest low + 1}",
2072 "\0<\0a\0>"
2073 "\xDC\x00"
2074 "\xE0\x00"
2075 "\0<\0/\0a\0>",
2076 false},
2077 // Group {largest low}{*}
2078 {"{largest low}{smallest high - 1}",
2079 "\0<\0a\0>"
2080 "\xDF\xFF"
2081 "\xD7\xFF"
2082 "\0<\0/\0a\0>",
2083 false},
2084 {"{largest low}{smallest high}",
2085 "\0<\0a\0>"
2086 "\xDF\xFF"
2087 "\xD8\x00"
2088 "\0<\0/\0a\0>",
2089 false},
2090 {"{largest low}{largest high}",
2091 "\0<\0a\0>"
2092 "\xDF\xFF"
2093 "\xDB\xFF"
2094 "\0<\0/\0a\0>",
2095 false},
2096 {"{largest low}{smallest low}",
2097 "\0<\0a\0>"
2098 "\xDF\xFF"
2099 "\xDC\x00"
2100 "\0<\0/\0a\0>",
2101 false},
2102 {"{largest low}{largest low}",
2103 "\0<\0a\0>"
2104 "\xDF\xFF"
2105 "\xDF\xFF"
2106 "\0<\0/\0a\0>",
2107 false},
2108 {"{largest low}{largest low + 1}",
2109 "\0<\0a\0>"
2110 "\xDF\xFF"
2111 "\xE0\x00"
2112 "\0<\0/\0a\0>",
2113 false},
2114 // Group {largest low + 1}{*}
2115 {"{largest low + 1}{smallest high - 1}",
2116 "\0<\0a\0>"
2117 "\xE0\x00"
2118 "\xD7\xFF"
2119 "\0<\0/\0a\0>",
2120 true},
2121 {"{largest low + 1}{smallest high}",
2122 "\0<\0a\0>"
2123 "\xE0\x00"
2124 "\xD8\x00"
2125 "\0<\0/\0a\0>",
2126 false},
2127 {"{largest low + 1}{largest high}",
2128 "\0<\0a\0>"
2129 "\xE0\x00"
2130 "\xDB\xFF"
2131 "\0<\0/\0a\0>",
2132 false},
2133 {"{largest low + 1}{smallest low}",
2134 "\0<\0a\0>"
2135 "\xE0\x00"
2136 "\xDC\x00"
2137 "\0<\0/\0a\0>",
2138 false},
2139 {"{largest low + 1}{largest low}",
2140 "\0<\0a\0>"
2141 "\xE0\x00"
2142 "\xDF\xFF"
2143 "\0<\0/\0a\0>",
2144 false},
2145 {"{largest low + 1}{largest low + 1}",
2146 "\0<\0a\0>"
2147 "\xE0\x00"
2148 "\xE0\x00"
2149 "\0<\0/\0a\0>",
2150 true},
2151 };
2152
2153 for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) {
2154 set_subtest("%s", testCases[i].idea);
2155
2156 const int lenBytes = /*<a>*/ 6 + /*first*/ 2 + /*second*/ 2 + /*</a>*/ 8;
2157 const bool expectedSuccess = testCases[i].expectedSuccess;
2158 const enum XML_Status expectedStatus
2159 = (expectedSuccess ? XML_STATUS_OK : XML_STATUS_ERROR);
2160
2161 const char *const bigEndian = testCases[i].content;
2162 char *const littleEndian = utf16_dup_flipped(bigEndian, lenBytes);
2163 assert_true(littleEndian != NULL);
2164 const char *endianCases[] = {bigEndian, littleEndian};
2165
2166 for (size_t j = 0; j < sizeof(endianCases) / sizeof(endianCases[0]); j++) {
2167 const char *text = endianCases[j];
2168
2169 assert_true(text[lenBytes] == '\0'); // self-test
2170 assert_true((text[0] == '\0')
2171 != (text[lenBytes - 1] == '\0')); // self-test
2172
2173 XML_Parser parser = XML_ParserCreate(NULL);
2174 assert_true(parser != NULL);
2175
2176 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, lenBytes, XML_TRUE)
2177 == expectedStatus);
2178 if (! expectedSuccess) {
2179 assert_true(XML_GetErrorCode(parser) == XML_ERROR_INVALID_TOKEN);
2180 }
2181
2182 XML_ParserFree(parser);
2183 }
2184
2185 free(littleEndian);
2186 }
2187 }
2188 END_TEST
2189
START_TEST(test_bad_cdata)2190 START_TEST(test_bad_cdata) {
2191 struct CaseData {
2192 const char *text;
2193 enum XML_Error expectedError;
2194 };
2195
2196 struct CaseData cases[]
2197 = {{"<a><", XML_ERROR_UNCLOSED_TOKEN},
2198 {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
2199 {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
2200 {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
2201 {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
2202 {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
2203 {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
2204 {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
2205
2206 {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
2207 {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
2208 {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
2209
2210 {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
2211 {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
2212 {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
2213 {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
2214 {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
2215 {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
2216 {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
2217
2218 {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
2219 {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
2220 {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}};
2221
2222 size_t i = 0;
2223 for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
2224 set_subtest("%s", cases[i].text);
2225 const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
2226 g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE);
2227 const enum XML_Error actualError = XML_GetErrorCode(g_parser);
2228
2229 assert(actualStatus == XML_STATUS_ERROR);
2230
2231 if (actualError != cases[i].expectedError) {
2232 char message[100];
2233 snprintf(message, sizeof(message),
2234 "Expected error %d but got error %d for case %u: \"%s\"\n",
2235 cases[i].expectedError, actualError, (unsigned int)i + 1,
2236 cases[i].text);
2237 fail(message);
2238 }
2239
2240 XML_ParserReset(g_parser, NULL);
2241 }
2242 }
2243 END_TEST
2244
2245 /* Test failures in UTF-16 CDATA */
START_TEST(test_bad_cdata_utf16)2246 START_TEST(test_bad_cdata_utf16) {
2247 struct CaseData {
2248 size_t text_bytes;
2249 const char *text;
2250 enum XML_Error expected_error;
2251 };
2252
2253 const char prolog[] = "\0<\0?\0x\0m\0l\0"
2254 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2255 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2256 "1\0"
2257 "6\0'"
2258 "\0?\0>\0\n"
2259 "\0<\0a\0>";
2260 struct CaseData cases[] = {
2261 {1, "\0", XML_ERROR_UNCLOSED_TOKEN},
2262 {2, "\0<", XML_ERROR_UNCLOSED_TOKEN},
2263 {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN},
2264 {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN},
2265 {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN},
2266 {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN},
2267 {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN},
2268 {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN},
2269 {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN},
2270 {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN},
2271 {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN},
2272 {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN},
2273 {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN},
2274 {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN},
2275 {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN},
2276 {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN},
2277 {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN},
2278 {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION},
2279 {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION},
2280 {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION},
2281 /* Now add a four-byte UTF-16 character */
2282 {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8",
2283 XML_ERROR_UNCLOSED_CDATA_SECTION},
2284 {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR},
2285 {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd",
2286 XML_ERROR_PARTIAL_CHAR},
2287 {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e",
2288 XML_ERROR_UNCLOSED_CDATA_SECTION}};
2289 size_t i;
2290
2291 for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) {
2292 set_subtest("case %lu", (long unsigned)(i + 1));
2293 enum XML_Status actual_status;
2294 enum XML_Error actual_error;
2295
2296 if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1,
2297 XML_FALSE)
2298 == XML_STATUS_ERROR)
2299 xml_failure(g_parser);
2300 actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text,
2301 (int)cases[i].text_bytes, XML_TRUE);
2302 assert(actual_status == XML_STATUS_ERROR);
2303 actual_error = XML_GetErrorCode(g_parser);
2304 if (actual_error != cases[i].expected_error) {
2305 char message[1024];
2306
2307 snprintf(message, sizeof(message),
2308 "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR
2309 ") for case %lu\n",
2310 cases[i].expected_error,
2311 XML_ErrorString(cases[i].expected_error), actual_error,
2312 XML_ErrorString(actual_error), (long unsigned)(i + 1));
2313 fail(message);
2314 }
2315 XML_ParserReset(g_parser, NULL);
2316 }
2317 }
2318 END_TEST
2319
2320 /* Test stopping the parser in cdata handler */
START_TEST(test_stop_parser_between_cdata_calls)2321 START_TEST(test_stop_parser_between_cdata_calls) {
2322 const char *text = long_cdata_text;
2323
2324 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2325 g_resumable = XML_FALSE;
2326 expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler");
2327 }
2328 END_TEST
2329
2330 /* Test suspending the parser in cdata handler */
START_TEST(test_suspend_parser_between_cdata_calls)2331 START_TEST(test_suspend_parser_between_cdata_calls) {
2332 if (g_chunkSize != 0) {
2333 // this test does not use SINGLE_BYTES, because of suspension
2334 return;
2335 }
2336
2337 const char *text = long_cdata_text;
2338 enum XML_Status result;
2339
2340 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2341 g_resumable = XML_TRUE;
2342 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
2343 // we won't know exactly how much input we actually managed to give Expat.
2344 result = XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE);
2345 if (result != XML_STATUS_SUSPENDED) {
2346 if (result == XML_STATUS_ERROR)
2347 xml_failure(g_parser);
2348 fail("Parse not suspended in CDATA handler");
2349 }
2350 if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
2351 xml_failure(g_parser);
2352 }
2353 END_TEST
2354
2355 /* Test memory allocation functions */
START_TEST(test_memory_allocation)2356 START_TEST(test_memory_allocation) {
2357 char *buffer = (char *)XML_MemMalloc(g_parser, 256);
2358 char *p;
2359
2360 if (buffer == NULL) {
2361 fail("Allocation failed");
2362 } else {
2363 /* Try writing to memory; some OSes try to cheat! */
2364 buffer[0] = 'T';
2365 buffer[1] = 'E';
2366 buffer[2] = 'S';
2367 buffer[3] = 'T';
2368 buffer[4] = '\0';
2369 if (strcmp(buffer, "TEST") != 0) {
2370 fail("Memory not writable");
2371 } else {
2372 p = (char *)XML_MemRealloc(g_parser, buffer, 512);
2373 if (p == NULL) {
2374 fail("Reallocation failed");
2375 } else {
2376 /* Write again, just to be sure */
2377 buffer = p;
2378 buffer[0] = 'V';
2379 if (strcmp(buffer, "VEST") != 0) {
2380 fail("Reallocated memory not writable");
2381 }
2382 }
2383 }
2384 XML_MemFree(g_parser, buffer);
2385 }
2386 }
2387 END_TEST
2388
2389 /* Test XML_DefaultCurrent() passes handling on correctly */
START_TEST(test_default_current)2390 START_TEST(test_default_current) {
2391 const char *text = "<doc>hell]</doc>";
2392 const char *entity_text = "<!DOCTYPE doc [\n"
2393 "<!ENTITY entity '%'>\n"
2394 "]>\n"
2395 "<doc>&entity;</doc>";
2396
2397 set_subtest("with defaulting");
2398 {
2399 struct handler_record_list storage;
2400 storage.count = 0;
2401 XML_SetDefaultHandler(g_parser, record_default_handler);
2402 XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2403 XML_SetUserData(g_parser, &storage);
2404 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2405 == XML_STATUS_ERROR)
2406 xml_failure(g_parser);
2407 int i = 0;
2408 assert_record_handler_called(&storage, i++, "record_default_handler", 5);
2409 // we should have gotten one or more cdata callbacks, totaling 5 chars
2410 int cdata_len_remaining = 5;
2411 while (cdata_len_remaining > 0) {
2412 const struct handler_record_entry *c_entry
2413 = handler_record_get(&storage, i++);
2414 assert_true(strcmp(c_entry->name, "record_cdata_handler") == 0);
2415 assert_true(c_entry->arg > 0);
2416 assert_true(c_entry->arg <= cdata_len_remaining);
2417 cdata_len_remaining -= c_entry->arg;
2418 // default handler must follow, with the exact same len argument.
2419 assert_record_handler_called(&storage, i++, "record_default_handler",
2420 c_entry->arg);
2421 }
2422 assert_record_handler_called(&storage, i++, "record_default_handler", 6);
2423 assert_true(storage.count == i);
2424 }
2425
2426 /* Again, without the defaulting */
2427 set_subtest("no defaulting");
2428 {
2429 struct handler_record_list storage;
2430 storage.count = 0;
2431 XML_ParserReset(g_parser, NULL);
2432 XML_SetDefaultHandler(g_parser, record_default_handler);
2433 XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
2434 XML_SetUserData(g_parser, &storage);
2435 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2436 == XML_STATUS_ERROR)
2437 xml_failure(g_parser);
2438 int i = 0;
2439 assert_record_handler_called(&storage, i++, "record_default_handler", 5);
2440 // we should have gotten one or more cdata callbacks, totaling 5 chars
2441 int cdata_len_remaining = 5;
2442 while (cdata_len_remaining > 0) {
2443 const struct handler_record_entry *c_entry
2444 = handler_record_get(&storage, i++);
2445 assert_true(strcmp(c_entry->name, "record_cdata_nodefault_handler") == 0);
2446 assert_true(c_entry->arg > 0);
2447 assert_true(c_entry->arg <= cdata_len_remaining);
2448 cdata_len_remaining -= c_entry->arg;
2449 }
2450 assert_record_handler_called(&storage, i++, "record_default_handler", 6);
2451 assert_true(storage.count == i);
2452 }
2453
2454 /* Now with an internal entity to complicate matters */
2455 set_subtest("with internal entity");
2456 {
2457 struct handler_record_list storage;
2458 storage.count = 0;
2459 XML_ParserReset(g_parser, NULL);
2460 XML_SetDefaultHandler(g_parser, record_default_handler);
2461 XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2462 XML_SetUserData(g_parser, &storage);
2463 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2464 XML_TRUE)
2465 == XML_STATUS_ERROR)
2466 xml_failure(g_parser);
2467 /* The default handler suppresses the entity */
2468 assert_record_handler_called(&storage, 0, "record_default_handler", 9);
2469 assert_record_handler_called(&storage, 1, "record_default_handler", 1);
2470 assert_record_handler_called(&storage, 2, "record_default_handler", 3);
2471 assert_record_handler_called(&storage, 3, "record_default_handler", 1);
2472 assert_record_handler_called(&storage, 4, "record_default_handler", 1);
2473 assert_record_handler_called(&storage, 5, "record_default_handler", 1);
2474 assert_record_handler_called(&storage, 6, "record_default_handler", 8);
2475 assert_record_handler_called(&storage, 7, "record_default_handler", 1);
2476 assert_record_handler_called(&storage, 8, "record_default_handler", 6);
2477 assert_record_handler_called(&storage, 9, "record_default_handler", 1);
2478 assert_record_handler_called(&storage, 10, "record_default_handler", 7);
2479 assert_record_handler_called(&storage, 11, "record_default_handler", 1);
2480 assert_record_handler_called(&storage, 12, "record_default_handler", 1);
2481 assert_record_handler_called(&storage, 13, "record_default_handler", 1);
2482 assert_record_handler_called(&storage, 14, "record_default_handler", 1);
2483 assert_record_handler_called(&storage, 15, "record_default_handler", 1);
2484 assert_record_handler_called(&storage, 16, "record_default_handler", 5);
2485 assert_record_handler_called(&storage, 17, "record_default_handler", 8);
2486 assert_record_handler_called(&storage, 18, "record_default_handler", 6);
2487 assert_true(storage.count == 19);
2488 }
2489
2490 /* Again, with a skip handler */
2491 set_subtest("with skip handler");
2492 {
2493 struct handler_record_list storage;
2494 storage.count = 0;
2495 XML_ParserReset(g_parser, NULL);
2496 XML_SetDefaultHandler(g_parser, record_default_handler);
2497 XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2498 XML_SetSkippedEntityHandler(g_parser, record_skip_handler);
2499 XML_SetUserData(g_parser, &storage);
2500 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2501 XML_TRUE)
2502 == XML_STATUS_ERROR)
2503 xml_failure(g_parser);
2504 /* The default handler suppresses the entity */
2505 assert_record_handler_called(&storage, 0, "record_default_handler", 9);
2506 assert_record_handler_called(&storage, 1, "record_default_handler", 1);
2507 assert_record_handler_called(&storage, 2, "record_default_handler", 3);
2508 assert_record_handler_called(&storage, 3, "record_default_handler", 1);
2509 assert_record_handler_called(&storage, 4, "record_default_handler", 1);
2510 assert_record_handler_called(&storage, 5, "record_default_handler", 1);
2511 assert_record_handler_called(&storage, 6, "record_default_handler", 8);
2512 assert_record_handler_called(&storage, 7, "record_default_handler", 1);
2513 assert_record_handler_called(&storage, 8, "record_default_handler", 6);
2514 assert_record_handler_called(&storage, 9, "record_default_handler", 1);
2515 assert_record_handler_called(&storage, 10, "record_default_handler", 7);
2516 assert_record_handler_called(&storage, 11, "record_default_handler", 1);
2517 assert_record_handler_called(&storage, 12, "record_default_handler", 1);
2518 assert_record_handler_called(&storage, 13, "record_default_handler", 1);
2519 assert_record_handler_called(&storage, 14, "record_default_handler", 1);
2520 assert_record_handler_called(&storage, 15, "record_default_handler", 1);
2521 assert_record_handler_called(&storage, 16, "record_default_handler", 5);
2522 assert_record_handler_called(&storage, 17, "record_skip_handler", 0);
2523 assert_record_handler_called(&storage, 18, "record_default_handler", 6);
2524 assert_true(storage.count == 19);
2525 }
2526
2527 /* This time, allow the entity through */
2528 set_subtest("allow entity");
2529 {
2530 struct handler_record_list storage;
2531 storage.count = 0;
2532 XML_ParserReset(g_parser, NULL);
2533 XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
2534 XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2535 XML_SetUserData(g_parser, &storage);
2536 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2537 XML_TRUE)
2538 == XML_STATUS_ERROR)
2539 xml_failure(g_parser);
2540 assert_record_handler_called(&storage, 0, "record_default_handler", 9);
2541 assert_record_handler_called(&storage, 1, "record_default_handler", 1);
2542 assert_record_handler_called(&storage, 2, "record_default_handler", 3);
2543 assert_record_handler_called(&storage, 3, "record_default_handler", 1);
2544 assert_record_handler_called(&storage, 4, "record_default_handler", 1);
2545 assert_record_handler_called(&storage, 5, "record_default_handler", 1);
2546 assert_record_handler_called(&storage, 6, "record_default_handler", 8);
2547 assert_record_handler_called(&storage, 7, "record_default_handler", 1);
2548 assert_record_handler_called(&storage, 8, "record_default_handler", 6);
2549 assert_record_handler_called(&storage, 9, "record_default_handler", 1);
2550 assert_record_handler_called(&storage, 10, "record_default_handler", 7);
2551 assert_record_handler_called(&storage, 11, "record_default_handler", 1);
2552 assert_record_handler_called(&storage, 12, "record_default_handler", 1);
2553 assert_record_handler_called(&storage, 13, "record_default_handler", 1);
2554 assert_record_handler_called(&storage, 14, "record_default_handler", 1);
2555 assert_record_handler_called(&storage, 15, "record_default_handler", 1);
2556 assert_record_handler_called(&storage, 16, "record_default_handler", 5);
2557 assert_record_handler_called(&storage, 17, "record_cdata_handler", 1);
2558 assert_record_handler_called(&storage, 18, "record_default_handler", 1);
2559 assert_record_handler_called(&storage, 19, "record_default_handler", 6);
2560 assert_true(storage.count == 20);
2561 }
2562
2563 /* Finally, without passing the cdata to the default handler */
2564 set_subtest("not passing cdata");
2565 {
2566 struct handler_record_list storage;
2567 storage.count = 0;
2568 XML_ParserReset(g_parser, NULL);
2569 XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
2570 XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
2571 XML_SetUserData(g_parser, &storage);
2572 if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2573 XML_TRUE)
2574 == XML_STATUS_ERROR)
2575 xml_failure(g_parser);
2576 assert_record_handler_called(&storage, 0, "record_default_handler", 9);
2577 assert_record_handler_called(&storage, 1, "record_default_handler", 1);
2578 assert_record_handler_called(&storage, 2, "record_default_handler", 3);
2579 assert_record_handler_called(&storage, 3, "record_default_handler", 1);
2580 assert_record_handler_called(&storage, 4, "record_default_handler", 1);
2581 assert_record_handler_called(&storage, 5, "record_default_handler", 1);
2582 assert_record_handler_called(&storage, 6, "record_default_handler", 8);
2583 assert_record_handler_called(&storage, 7, "record_default_handler", 1);
2584 assert_record_handler_called(&storage, 8, "record_default_handler", 6);
2585 assert_record_handler_called(&storage, 9, "record_default_handler", 1);
2586 assert_record_handler_called(&storage, 10, "record_default_handler", 7);
2587 assert_record_handler_called(&storage, 11, "record_default_handler", 1);
2588 assert_record_handler_called(&storage, 12, "record_default_handler", 1);
2589 assert_record_handler_called(&storage, 13, "record_default_handler", 1);
2590 assert_record_handler_called(&storage, 14, "record_default_handler", 1);
2591 assert_record_handler_called(&storage, 15, "record_default_handler", 1);
2592 assert_record_handler_called(&storage, 16, "record_default_handler", 5);
2593 assert_record_handler_called(&storage, 17, "record_cdata_nodefault_handler",
2594 1);
2595 assert_record_handler_called(&storage, 18, "record_default_handler", 6);
2596 assert_true(storage.count == 19);
2597 }
2598 }
2599 END_TEST
2600
2601 /* Test DTD element parsing code paths */
START_TEST(test_dtd_elements)2602 START_TEST(test_dtd_elements) {
2603 const char *text = "<!DOCTYPE doc [\n"
2604 "<!ELEMENT doc (chapter)>\n"
2605 "<!ELEMENT chapter (#PCDATA)>\n"
2606 "]>\n"
2607 "<doc><chapter>Wombats are go</chapter></doc>";
2608
2609 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
2610 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2611 == XML_STATUS_ERROR)
2612 xml_failure(g_parser);
2613 }
2614 END_TEST
2615
2616 static void XMLCALL
element_decl_check_model(void * userData,const XML_Char * name,XML_Content * model)2617 element_decl_check_model(void *userData, const XML_Char *name,
2618 XML_Content *model) {
2619 UNUSED_P(userData);
2620 uint32_t errorFlags = 0;
2621
2622 /* Expected model array structure is this:
2623 * [0] (type 6, quant 0)
2624 * [1] (type 5, quant 0)
2625 * [3] (type 4, quant 0, name "bar")
2626 * [4] (type 4, quant 0, name "foo")
2627 * [5] (type 4, quant 3, name "xyz")
2628 * [2] (type 4, quant 2, name "zebra")
2629 */
2630 errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0));
2631 errorFlags |= ((model != NULL) ? 0 : (1u << 1));
2632
2633 if (model != NULL) {
2634 errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2));
2635 errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3));
2636 errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4));
2637 errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5));
2638 errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6));
2639
2640 errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7));
2641 errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8));
2642 errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9));
2643 errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10));
2644 errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11));
2645
2646 errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12));
2647 errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13));
2648 errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14));
2649 errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15));
2650 errorFlags
2651 |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16));
2652
2653 errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17));
2654 errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18));
2655 errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19));
2656 errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20));
2657 errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21));
2658
2659 errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22));
2660 errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23));
2661 errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24));
2662 errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25));
2663 errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26));
2664
2665 errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27));
2666 errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28));
2667 errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29));
2668 errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30));
2669 errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31));
2670 }
2671
2672 XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags);
2673 XML_FreeContentModel(g_parser, model);
2674 }
2675
START_TEST(test_dtd_elements_nesting)2676 START_TEST(test_dtd_elements_nesting) {
2677 // Payload inspired by a test in Perl's XML::Parser
2678 const char *text = "<!DOCTYPE foo [\n"
2679 "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n"
2680 "]>\n"
2681 "<foo/>";
2682
2683 XML_SetUserData(g_parser, (void *)(uintptr_t)-1);
2684
2685 XML_SetElementDeclHandler(g_parser, element_decl_check_model);
2686 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2687 == XML_STATUS_ERROR)
2688 xml_failure(g_parser);
2689
2690 if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0)
2691 fail("Element declaration model regression detected");
2692 }
2693 END_TEST
2694
2695 /* Test foreign DTD handling */
START_TEST(test_set_foreign_dtd)2696 START_TEST(test_set_foreign_dtd) {
2697 const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
2698 const char *text2 = "<doc>&entity;</doc>";
2699 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2700
2701 /* Check hash salt is passed through too */
2702 xmlSetHashSalt(g_parser, 0x12345678);
2703 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2704 XML_SetUserData(g_parser, &test_data);
2705 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2706 /* Add a default handler to exercise more code paths */
2707 XML_SetDefaultHandler(g_parser, dummy_default_handler);
2708 if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2709 fail("Could not set foreign DTD");
2710 if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
2711 == XML_STATUS_ERROR)
2712 xml_failure(g_parser);
2713
2714 /* Ensure that trying to set the DTD after parsing has started
2715 * is faulted, even if it's the same setting.
2716 */
2717 if (XML_UseForeignDTD(g_parser, XML_TRUE)
2718 != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
2719 fail("Failed to reject late foreign DTD setting");
2720 /* Ditto for the hash salt */
2721 if (xmlSetHashSalt(g_parser, 0x23456789))
2722 fail("Failed to reject late hash salt change");
2723
2724 /* Now finish the parse */
2725 if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
2726 == XML_STATUS_ERROR)
2727 xml_failure(g_parser);
2728 }
2729 END_TEST
2730
2731 /* Test foreign DTD handling with a failing NotStandalone handler */
START_TEST(test_foreign_dtd_not_standalone)2732 START_TEST(test_foreign_dtd_not_standalone) {
2733 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2734 "<doc>&entity;</doc>";
2735 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2736
2737 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2738 XML_SetUserData(g_parser, &test_data);
2739 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2740 XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
2741 if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2742 fail("Could not set foreign DTD");
2743 expect_failure(text, XML_ERROR_NOT_STANDALONE,
2744 "NotStandalonehandler failed to reject");
2745 }
2746 END_TEST
2747
2748 /* Test invalid character in a foreign DTD is faulted */
START_TEST(test_invalid_foreign_dtd)2749 START_TEST(test_invalid_foreign_dtd) {
2750 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2751 "<doc>&entity;</doc>";
2752 ExtFaults test_data
2753 = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN};
2754
2755 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2756 XML_SetUserData(g_parser, &test_data);
2757 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
2758 XML_UseForeignDTD(g_parser, XML_TRUE);
2759 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
2760 "Bad DTD should not have been accepted");
2761 }
2762 END_TEST
2763
2764 /* Test foreign DTD use with a doctype */
START_TEST(test_foreign_dtd_with_doctype)2765 START_TEST(test_foreign_dtd_with_doctype) {
2766 const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
2767 "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
2768 const char *text2 = "<doc>&entity;</doc>";
2769 ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2770
2771 /* Check hash salt is passed through too */
2772 xmlSetHashSalt(g_parser, 0x12345678);
2773 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2774 XML_SetUserData(g_parser, &test_data);
2775 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2776 /* Add a default handler to exercise more code paths */
2777 XML_SetDefaultHandler(g_parser, dummy_default_handler);
2778 if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2779 fail("Could not set foreign DTD");
2780 if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
2781 == XML_STATUS_ERROR)
2782 xml_failure(g_parser);
2783
2784 /* Ensure that trying to set the DTD after parsing has started
2785 * is faulted, even if it's the same setting.
2786 */
2787 if (XML_UseForeignDTD(g_parser, XML_TRUE)
2788 != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
2789 fail("Failed to reject late foreign DTD setting");
2790 /* Ditto for the hash salt */
2791 if (xmlSetHashSalt(g_parser, 0x23456789))
2792 fail("Failed to reject late hash salt change");
2793
2794 /* Now finish the parse */
2795 if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
2796 == XML_STATUS_ERROR)
2797 xml_failure(g_parser);
2798 }
2799 END_TEST
2800
2801 /* Test XML_UseForeignDTD with no external subset present */
START_TEST(test_foreign_dtd_without_external_subset)2802 START_TEST(test_foreign_dtd_without_external_subset) {
2803 const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n"
2804 "<doc>&foo;</doc>";
2805
2806 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2807 XML_SetUserData(g_parser, NULL);
2808 XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
2809 XML_UseForeignDTD(g_parser, XML_TRUE);
2810 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2811 == XML_STATUS_ERROR)
2812 xml_failure(g_parser);
2813 }
2814 END_TEST
2815
START_TEST(test_empty_foreign_dtd)2816 START_TEST(test_empty_foreign_dtd) {
2817 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2818 "<doc>&entity;</doc>";
2819
2820 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2821 XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
2822 XML_UseForeignDTD(g_parser, XML_TRUE);
2823 expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
2824 "Undefined entity not faulted");
2825 }
2826 END_TEST
2827
2828 /* Test XML Base is set and unset appropriately */
START_TEST(test_set_base)2829 START_TEST(test_set_base) {
2830 const XML_Char *old_base;
2831 const XML_Char *new_base = XCS("/local/file/name.xml");
2832
2833 old_base = XML_GetBase(g_parser);
2834 if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
2835 fail("Unable to set base");
2836 if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
2837 fail("Base setting not correct");
2838 if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
2839 fail("Unable to NULL base");
2840 if (XML_GetBase(g_parser) != NULL)
2841 fail("Base setting not nulled");
2842 XML_SetBase(g_parser, old_base);
2843 }
2844 END_TEST
2845
2846 /* Test attribute counts, indexing, etc */
START_TEST(test_attributes)2847 START_TEST(test_attributes) {
2848 const char *text = "<!DOCTYPE doc [\n"
2849 "<!ELEMENT doc (tag)>\n"
2850 "<!ATTLIST doc id ID #REQUIRED>\n"
2851 "]>"
2852 "<doc a='1' id='one' b='2'>"
2853 "<tag c='3'/>"
2854 "</doc>";
2855 AttrInfo doc_info[] = {{XCS("a"), XCS("1")},
2856 {XCS("b"), XCS("2")},
2857 {XCS("id"), XCS("one")},
2858 {NULL, NULL}};
2859 AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
2860 ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), doc_info},
2861 {XCS("tag"), 1, 0, NULL, tag_info},
2862 {NULL, 0, 0, NULL, NULL}};
2863
2864 XML_Parser parser = XML_ParserCreate(NULL);
2865 assert_true(parser != NULL);
2866 ParserAndElementInfo parserAndElementInfos = {
2867 parser,
2868 info,
2869 };
2870
2871 XML_SetStartElementHandler(parser, counting_start_element_handler);
2872 XML_SetUserData(parser, &parserAndElementInfos);
2873 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
2874 == XML_STATUS_ERROR)
2875 xml_failure(parser);
2876
2877 XML_ParserFree(parser);
2878 }
2879 END_TEST
2880
START_TEST(test_duplicate_cdata_attribute)2881 START_TEST(test_duplicate_cdata_attribute) {
2882 /*
2883 https://www.w3.org/TR/xml/#attdecls
2884
2885 Test the following statement from the linked specification:
2886 When more than one definition is provided for the same attribute of a given
2887 element type, the first declaration is binding and later declarations are
2888 ignored.
2889 */
2890
2891 const char *text
2892 = "<!DOCTYPE doc [\n"
2893 " <!ATTLIST doc attribute CDATA 'expected' attribute CDATA 'ignored'>\n"
2894 "]>\n"
2895 "<doc/>\n";
2896 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}};
2897 ElementInfo info[]
2898 = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
2899
2900 XML_Parser parser = XML_ParserCreate(NULL);
2901 assert_true(parser != NULL);
2902
2903 ParserAndElementInfo parserAndElementInfos = {
2904 parser,
2905 info,
2906 };
2907
2908 XML_SetStartElementHandler(parser, counting_start_element_handler);
2909 XML_SetUserData(parser, &parserAndElementInfos);
2910
2911 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
2912 != XML_STATUS_OK)
2913 xml_failure(parser);
2914
2915 XML_ParserFree(parser);
2916 }
2917 END_TEST
2918
START_TEST(test_duplicate_id_attribute_1)2919 START_TEST(test_duplicate_id_attribute_1) {
2920 /*
2921 https://www.w3.org/TR/xml/#attdecls
2922
2923 Test the following statement from the linked specification:
2924 When more than one definition is provided for the same attribute of a given
2925 element type, the first declaration is binding and later declarations are
2926 ignored.
2927 */
2928
2929 const char *text
2930 = "<!DOCTYPE doc [\n"
2931 " <!ATTLIST doc identifier CDATA 'expected' identifier ID #REQUIRED>\n"
2932 "]>\n"
2933 "<doc/>\n";
2934 AttrInfo doc_info[] = {{XCS("identifier"), XCS("expected")}, {NULL, NULL}};
2935 ElementInfo info[]
2936 = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
2937
2938 XML_Parser parser = XML_ParserCreate(NULL);
2939 assert_true(parser != NULL);
2940
2941 ParserAndElementInfo parserAndElementInfos = {
2942 parser,
2943 info,
2944 };
2945
2946 XML_SetStartElementHandler(parser, counting_start_element_handler);
2947 XML_SetUserData(parser, &parserAndElementInfos);
2948
2949 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
2950 != XML_STATUS_OK)
2951 xml_failure(parser);
2952
2953 XML_ParserFree(parser);
2954 }
2955 END_TEST
2956
START_TEST(test_duplicate_id_attribute_2)2957 START_TEST(test_duplicate_id_attribute_2) {
2958 /*
2959 https://www.w3.org/TR/xml/#attdecls
2960
2961 Test the following statement from the linked specification:
2962 When more than one definition is provided for the same attribute of a given
2963 element type, the first declaration is binding and later declarations are
2964 ignored.
2965 */
2966
2967 const char *text
2968 = "<!DOCTYPE doc [\n"
2969 " <!ATTLIST doc identifier ID #REQUIRED identifier CDATA 'unexpected'>\n"
2970 "]>\n"
2971 "<doc/>\n";
2972 AttrInfo doc_info[] = {{NULL, NULL}};
2973
2974 ElementInfo info[]
2975 = {{XCS("doc"), 0, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
2976
2977 XML_Parser parser = XML_ParserCreate(NULL);
2978 assert_true(parser != NULL);
2979
2980 ParserAndElementInfo parserAndElementInfos = {
2981 parser,
2982 info,
2983 };
2984
2985 XML_SetStartElementHandler(parser, counting_start_element_handler);
2986 XML_SetUserData(parser, &parserAndElementInfos);
2987
2988 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
2989 != XML_STATUS_OK)
2990 xml_failure(parser);
2991
2992 XML_ParserFree(parser);
2993 }
2994 END_TEST
2995
START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl)2996 START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl) {
2997 /*
2998 https://www.w3.org/TR/xml/#attdecls
2999
3000 Test the following statement from the linked specification:
3001 When more than one AttlistDecl is provided for a given element type,
3002 the contents of all those provided are merged.
3003 */
3004 const char *text = "<!DOCTYPE doc [\n"
3005 " <!ATTLIST doc attribute CDATA 'expected'>\n"
3006 " <!ATTLIST doc attribute CDATA 'ignored'>\n"
3007 "]>\n"
3008 "<doc/>\n";
3009 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}};
3010 ElementInfo info[]
3011 = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
3012
3013 XML_Parser parser = XML_ParserCreate(NULL);
3014 assert_true(parser != NULL);
3015
3016 ParserAndElementInfo parserAndElementInfos = {
3017 parser,
3018 info,
3019 };
3020
3021 XML_SetStartElementHandler(parser, counting_start_element_handler);
3022 XML_SetUserData(parser, &parserAndElementInfos);
3023
3024 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
3025 != XML_STATUS_OK)
3026 xml_failure(parser);
3027
3028 XML_ParserFree(parser);
3029 }
3030 END_TEST
3031
START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_2)3032 START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_2) {
3033 /*
3034 https://www.w3.org/TR/xml/#attdecls
3035
3036 Test the following statement from the linked specification:
3037 When more than one AttlistDecl is provided for a given element type,
3038 the contents of all those provided are merged.
3039 */
3040 const char *text = "<!DOCTYPE doc [\n"
3041 " <!ATTLIST doc attribute CDATA 'expected_doc'>\n"
3042 " <!ATTLIST tag attribute CDATA 'expected_tag'>\n"
3043 " <!ATTLIST doc attribute CDATA 'ignored_doc'>\n"
3044 "]>\n"
3045 "<doc><tag></tag></doc>\n";
3046 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, {NULL, NULL}};
3047 AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}};
3048 ElementInfo info[] = {{XCS("doc"), 0, 1, NULL, doc_info},
3049 {XCS("tag"), 0, 1, NULL, tag_info},
3050 {NULL, 0, 0, NULL, NULL}};
3051
3052 XML_Parser parser = XML_ParserCreate(NULL);
3053 assert_true(parser != NULL);
3054
3055 ParserAndElementInfo parserAndElementInfos = {
3056 parser,
3057 info,
3058 };
3059
3060 XML_SetStartElementHandler(parser, counting_start_element_handler);
3061 XML_SetUserData(parser, &parserAndElementInfos);
3062
3063 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
3064 != XML_STATUS_OK)
3065 xml_failure(parser);
3066
3067 XML_ParserFree(parser);
3068 }
3069 END_TEST
3070
START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_3)3071 START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_3) {
3072 /*
3073 https://www.w3.org/TR/xml/#attdecls
3074
3075 Test the following statement from the linked specification:
3076 When more than one AttlistDecl is provided for a given element type,
3077 the contents of all those provided are merged.
3078 */
3079 const char *text
3080 = "<!DOCTYPE doc [\n"
3081 " <!ATTLIST doc attribute CDATA 'expected_doc'>\n"
3082 " <!ATTLIST tag attribute CDATA 'expected_tag'>\n"
3083 " <!ATTLIST doc second_attribute CDATA 'second_expected_doc' attribute CDATA 'ignored_doc'>\n"
3084 "]>\n"
3085 "<doc><tag></tag></doc>\n";
3086 AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")},
3087 {XCS("second_attribute"), XCS("second_expected_doc")},
3088 {NULL, NULL}};
3089 AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}};
3090 ElementInfo info[] = {{XCS("doc"), 0, 2, NULL, doc_info},
3091 {XCS("tag"), 0, 1, NULL, tag_info},
3092 {NULL, 0, 0, NULL, NULL}};
3093
3094 XML_Parser parser = XML_ParserCreate(NULL);
3095 assert_true(parser != NULL);
3096
3097 ParserAndElementInfo parserAndElementInfos = {
3098 parser,
3099 info,
3100 };
3101
3102 XML_SetStartElementHandler(parser, counting_start_element_handler);
3103 XML_SetUserData(parser, &parserAndElementInfos);
3104
3105 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
3106 != XML_STATUS_OK)
3107 xml_failure(parser);
3108
3109 XML_ParserFree(parser);
3110 }
3111 END_TEST
3112
START_TEST(test_duplicate_id_attribute_multiple_attlistdecl)3113 START_TEST(test_duplicate_id_attribute_multiple_attlistdecl) {
3114 /*
3115 https://www.w3.org/TR/xml/#attdecls
3116
3117 Test the following statement from the linked specification:
3118 When more than one AttlistDecl is provided for a given element type,
3119 the contents of all those provided are merged.
3120 */
3121 const char *text = "<!DOCTYPE doc [\n"
3122 " <!ATTLIST doc identifier ID #REQUIRED>\n"
3123 " <!ATTLIST tag identifier CDATA 'identifier_tag'>\n"
3124 " <!ATTLIST doc identifier CDATA 'ignored'>\n"
3125 "]>\n"
3126 "<doc identifier='doc_identity'><tag></tag></doc>\n";
3127 AttrInfo doc_info[]
3128 = {{XCS("identifier"), XCS("doc_identity")}, {NULL, NULL}};
3129 AttrInfo tag_info[]
3130 = {{XCS("identifier"), XCS("identifier_tag")}, {NULL, NULL}};
3131 ElementInfo info[] = {{XCS("doc"), 1, 0, XCS("identifier"), doc_info},
3132 {XCS("tag"), 0, 1, NULL, tag_info},
3133 {NULL, 0, 0, NULL, NULL}};
3134
3135 XML_Parser parser = XML_ParserCreate(NULL);
3136 assert_true(parser != NULL);
3137
3138 ParserAndElementInfo parserAndElementInfos = {
3139 parser,
3140 info,
3141 };
3142
3143 XML_SetStartElementHandler(parser, counting_start_element_handler);
3144 XML_SetUserData(parser, &parserAndElementInfos);
3145
3146 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
3147 != XML_STATUS_OK)
3148 xml_failure(parser);
3149
3150 XML_ParserFree(parser);
3151 }
3152 END_TEST
3153
3154 static void XMLCALL
check_second_attr_normalization(void * userData,const XML_Char * name,const XML_Char ** atts)3155 check_second_attr_normalization(void *userData, const XML_Char *name,
3156 const XML_Char **atts) {
3157 int *const seen_second = userData;
3158 UNUSED_P(name);
3159
3160 for (size_t i = 0; atts[i] != NULL; i += 2) {
3161 const XML_Char *const key = atts[i];
3162 const XML_Char *const value = atts[i + 1];
3163 if (xcstrcmp(key, XCS("second")) != 0)
3164 continue;
3165 *seen_second = 1;
3166 /* Attribute "second" is not of type CDATA, so leading, trailing and
3167 * repeated whitespace is to be normalized away. */
3168 if (xcstrcmp(value, XCS("a b")) != 0)
3169 fail("Attribute of non-CDATA type was not whitespace-normalized");
3170 }
3171 }
3172
3173 static int XMLCALL
external_entity_attr_checker(XML_Parser parser,const XML_Char * context,const XML_Char * base,const XML_Char * systemId,const XML_Char * publicId)3174 external_entity_attr_checker(XML_Parser parser, const XML_Char *context,
3175 const XML_Char *base, const XML_Char *systemId,
3176 const XML_Char *publicId) {
3177 const char *const text = "<tag second=' a b '/>";
3178 UNUSED_P(base);
3179 UNUSED_P(systemId);
3180 UNUSED_P(publicId);
3181
3182 XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3183 if (ext_parser == NULL)
3184 fail("Could not create external entity parser");
3185
3186 if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3187 != XML_STATUS_OK)
3188 xml_failure(ext_parser);
3189
3190 XML_ParserFree(ext_parser);
3191 return XML_STATUS_OK;
3192 }
3193
START_TEST(test_default_attr_index_after_dtd_copy)3194 START_TEST(test_default_attr_index_after_dtd_copy) {
3195 /* Function storeAtts resolves member .attIndex of structure
3196 * NAME_AND_DEFAULT_ATTRIBUTE to tell whether an attribute value needs
3197 * whitespace normalization, so function dtdCopy needs to carry that index
3198 * over to the copy. Attribute "first" is declared before attribute
3199 * "second" so that a mixed-up index resolves to the wrong declaration.
3200 */
3201 const char *text = "<!DOCTYPE doc [\n"
3202 " <!ENTITY e SYSTEM 'entity.ent'>\n"
3203 " <!ELEMENT doc ANY>\n"
3204 " <!ELEMENT tag EMPTY>\n"
3205 " <!ATTLIST tag first CDATA #IMPLIED>\n"
3206 " <!ATTLIST tag second NMTOKENS #IMPLIED>\n"
3207 "]>\n"
3208 "<doc>&e;</doc>\n";
3209 int seen_second = 0;
3210
3211 XML_Parser parser = XML_ParserCreate(NULL);
3212 assert_true(parser != NULL);
3213 XML_SetUserData(parser, &seen_second);
3214 XML_SetExternalEntityRefHandler(parser, external_entity_attr_checker);
3215 XML_SetStartElementHandler(parser, check_second_attr_normalization);
3216
3217 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
3218 != XML_STATUS_OK)
3219 xml_failure(parser);
3220 if (! seen_second)
3221 fail("Attribute \"second\" has not been reported");
3222
3223 XML_ParserFree(parser);
3224 }
3225 END_TEST
3226
3227 /* Test reset works correctly in the middle of processing an internal
3228 * entity. Exercises some obscure code in XML_ParserReset().
3229 */
START_TEST(test_reset_in_entity)3230 START_TEST(test_reset_in_entity) {
3231 if (g_chunkSize != 0) {
3232 // this test does not use SINGLE_BYTES, because of suspension
3233 return;
3234 }
3235
3236 const char *text = "<!DOCTYPE doc [\n"
3237 "<!ENTITY wombat 'wom'>\n"
3238 "<!ENTITY entity 'hi &wom; there'>\n"
3239 "]>\n"
3240 "<doc>&entity;</doc>";
3241 XML_ParsingStatus status;
3242
3243 g_resumable = XML_TRUE;
3244 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
3245 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
3246 // we won't know exactly how much input we actually managed to give Expat.
3247 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
3248 == XML_STATUS_ERROR)
3249 xml_failure(g_parser);
3250 XML_GetParsingStatus(g_parser, &status);
3251 if (status.parsing != XML_SUSPENDED)
3252 fail("Parsing status not SUSPENDED");
3253 XML_ParserReset(g_parser, NULL);
3254 XML_GetParsingStatus(g_parser, &status);
3255 if (status.parsing != XML_INITIALIZED)
3256 fail("Parsing status doesn't reset to INITIALIZED");
3257 }
3258 END_TEST
3259
3260 /* Test that resume correctly passes through parse errors */
START_TEST(test_resume_invalid_parse)3261 START_TEST(test_resume_invalid_parse) {
3262 const char *text = "<doc>Hello</doc"; /* Missing closing wedge */
3263
3264 g_resumable = XML_TRUE;
3265 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
3266 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
3267 == XML_STATUS_ERROR)
3268 xml_failure(g_parser);
3269 if (XML_ResumeParser(g_parser) == XML_STATUS_OK)
3270 fail("Resumed invalid parse not faulted");
3271 if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN)
3272 fail("Invalid parse not correctly faulted");
3273 }
3274 END_TEST
3275
3276 /* Test that re-suspended parses are correctly passed through */
START_TEST(test_resume_resuspended)3277 START_TEST(test_resume_resuspended) {
3278 const char *text = "<doc>Hello<meep/>world</doc>";
3279
3280 g_resumable = XML_TRUE;
3281 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
3282 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
3283 == XML_STATUS_ERROR)
3284 xml_failure(g_parser);
3285 g_resumable = XML_TRUE;
3286 XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
3287 if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
3288 fail("Resumption not suspended");
3289 /* This one should succeed and finish up */
3290 if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
3291 xml_failure(g_parser);
3292 }
3293 END_TEST
3294
3295 /* Test that CDATA shows up correctly through a default handler */
START_TEST(test_cdata_default)3296 START_TEST(test_cdata_default) {
3297 const char *text = "<doc><![CDATA[Hello\nworld]]></doc>";
3298 const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>");
3299 CharData storage;
3300
3301 CharData_Init(&storage);
3302 XML_SetUserData(g_parser, &storage);
3303 XML_SetDefaultHandler(g_parser, accumulate_characters);
3304
3305 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3306 == XML_STATUS_ERROR)
3307 xml_failure(g_parser);
3308 CharData_CheckXMLChars(&storage, expected);
3309 }
3310 END_TEST
3311
3312 /* Test resetting a subordinate parser does exactly nothing */
START_TEST(test_subordinate_reset)3313 START_TEST(test_subordinate_reset) {
3314 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3315 "<!DOCTYPE doc SYSTEM 'foo'>\n"
3316 "<doc>&entity;</doc>";
3317
3318 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3319 XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter);
3320 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3321 == XML_STATUS_ERROR)
3322 xml_failure(g_parser);
3323 }
3324 END_TEST
3325
3326 /* Test suspending a subordinate parser */
START_TEST(test_subordinate_suspend)3327 START_TEST(test_subordinate_suspend) {
3328 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3329 "<!DOCTYPE doc SYSTEM 'foo'>\n"
3330 "<doc>&entity;</doc>";
3331
3332 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3333 XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender);
3334 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3335 == XML_STATUS_ERROR)
3336 xml_failure(g_parser);
3337 }
3338 END_TEST
3339
3340 /* Test suspending a subordinate parser from an XML declaration */
3341 /* Increases code coverage of the tests */
3342
START_TEST(test_subordinate_xdecl_suspend)3343 START_TEST(test_subordinate_xdecl_suspend) {
3344 const char *text
3345 = "<!DOCTYPE doc [\n"
3346 " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
3347 "]>\n"
3348 "<doc>&entity;</doc>";
3349
3350 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3351 XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
3352 g_resumable = XML_TRUE;
3353 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3354 == XML_STATUS_ERROR)
3355 xml_failure(g_parser);
3356 }
3357 END_TEST
3358
START_TEST(test_subordinate_xdecl_abort)3359 START_TEST(test_subordinate_xdecl_abort) {
3360 const char *text
3361 = "<!DOCTYPE doc [\n"
3362 " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
3363 "]>\n"
3364 "<doc>&entity;</doc>";
3365
3366 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3367 XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
3368 g_resumable = XML_FALSE;
3369 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3370 == XML_STATUS_ERROR)
3371 xml_failure(g_parser);
3372 }
3373 END_TEST
3374
3375 /* Test external entity fault handling with suspension */
START_TEST(test_ext_entity_invalid_suspended_parse)3376 START_TEST(test_ext_entity_invalid_suspended_parse) {
3377 const char *text = "<!DOCTYPE doc [\n"
3378 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3379 "]>\n"
3380 "<doc>&en;</doc>";
3381 ExtFaults faults[]
3382 = {{"<?xml version='1.0' encoding='us-ascii'?><",
3383 "Incomplete element declaration not faulted", NULL,
3384 XML_ERROR_UNCLOSED_TOKEN},
3385 {/* First two bytes of a three-byte char */
3386 "<?xml version='1.0' encoding='utf-8'?>\xe2\x82",
3387 "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
3388 {NULL, NULL, NULL, XML_ERROR_NONE}};
3389 ExtFaults *fault;
3390
3391 for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
3392 set_subtest("%s", fault->parse_text);
3393 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3394 XML_SetExternalEntityRefHandler(g_parser,
3395 external_entity_suspending_faulter);
3396 XML_SetUserData(g_parser, fault);
3397 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
3398 "Parser did not report external entity error");
3399 XML_ParserReset(g_parser, NULL);
3400 }
3401 }
3402 END_TEST
3403
3404 /* Test setting an explicit encoding */
START_TEST(test_explicit_encoding)3405 START_TEST(test_explicit_encoding) {
3406 const char *text1 = "<doc>Hello ";
3407 const char *text2 = " World</doc>";
3408
3409 /* Just check that we can set the encoding to NULL before starting */
3410 if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
3411 fail("Failed to initialise encoding to NULL");
3412 /* Say we are UTF-8 */
3413 if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK)
3414 fail("Failed to set explicit encoding");
3415 if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
3416 == XML_STATUS_ERROR)
3417 xml_failure(g_parser);
3418 /* Try to switch encodings mid-parse */
3419 if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR)
3420 fail("Allowed encoding change");
3421 if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
3422 == XML_STATUS_ERROR)
3423 xml_failure(g_parser);
3424 /* Try now the parse is over */
3425 if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
3426 fail("Failed to unset encoding");
3427 }
3428 END_TEST
3429
3430 /* Test handling of trailing CR (rather than newline) */
START_TEST(test_trailing_cr)3431 START_TEST(test_trailing_cr) {
3432 const char *text = "<doc>\r";
3433 int found_cr;
3434
3435 /* Try with a character handler, for code coverage */
3436 XML_SetCharacterDataHandler(g_parser, cr_cdata_handler);
3437 XML_SetUserData(g_parser, &found_cr);
3438 found_cr = 0;
3439 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3440 == XML_STATUS_OK)
3441 fail("Failed to fault unclosed doc");
3442 if (found_cr == 0)
3443 fail("Did not catch the carriage return");
3444 XML_ParserReset(g_parser, NULL);
3445
3446 /* Now with a default handler instead */
3447 XML_SetDefaultHandler(g_parser, cr_cdata_handler);
3448 XML_SetUserData(g_parser, &found_cr);
3449 found_cr = 0;
3450 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3451 == XML_STATUS_OK)
3452 fail("Failed to fault unclosed doc");
3453 if (found_cr == 0)
3454 fail("Did not catch default carriage return");
3455 }
3456 END_TEST
3457
3458 /* Test trailing CR in an external entity parse */
START_TEST(test_ext_entity_trailing_cr)3459 START_TEST(test_ext_entity_trailing_cr) {
3460 const char *text = "<!DOCTYPE doc [\n"
3461 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3462 "]>\n"
3463 "<doc>&en;</doc>";
3464 int found_cr;
3465
3466 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3467 XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher);
3468 XML_SetUserData(g_parser, &found_cr);
3469 found_cr = 0;
3470 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3471 != XML_STATUS_OK)
3472 xml_failure(g_parser);
3473 if (found_cr == 0)
3474 fail("No carriage return found");
3475 XML_ParserReset(g_parser, NULL);
3476
3477 /* Try again with a different trailing CR */
3478 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3479 XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher);
3480 XML_SetUserData(g_parser, &found_cr);
3481 found_cr = 0;
3482 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3483 != XML_STATUS_OK)
3484 xml_failure(g_parser);
3485 if (found_cr == 0)
3486 fail("No carriage return found");
3487 }
3488 END_TEST
3489
3490 /* Test handling of trailing square bracket */
START_TEST(test_trailing_rsqb)3491 START_TEST(test_trailing_rsqb) {
3492 const char *text8 = "<doc>]";
3493 const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000";
3494 int found_rsqb;
3495 int text8_len = (int)strlen(text8);
3496
3497 XML_SetCharacterDataHandler(g_parser, rsqb_handler);
3498 XML_SetUserData(g_parser, &found_rsqb);
3499 found_rsqb = 0;
3500 if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE)
3501 == XML_STATUS_OK)
3502 fail("Failed to fault unclosed doc");
3503 if (found_rsqb == 0)
3504 fail("Did not catch the right square bracket");
3505
3506 /* Try again with a different encoding */
3507 XML_ParserReset(g_parser, NULL);
3508 XML_SetCharacterDataHandler(g_parser, rsqb_handler);
3509 XML_SetUserData(g_parser, &found_rsqb);
3510 found_rsqb = 0;
3511 if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
3512 XML_TRUE)
3513 == XML_STATUS_OK)
3514 fail("Failed to fault unclosed doc");
3515 if (found_rsqb == 0)
3516 fail("Did not catch the right square bracket");
3517
3518 /* And finally with a default handler */
3519 XML_ParserReset(g_parser, NULL);
3520 XML_SetDefaultHandler(g_parser, rsqb_handler);
3521 XML_SetUserData(g_parser, &found_rsqb);
3522 found_rsqb = 0;
3523 if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
3524 XML_TRUE)
3525 == XML_STATUS_OK)
3526 fail("Failed to fault unclosed doc");
3527 if (found_rsqb == 0)
3528 fail("Did not catch the right square bracket");
3529 }
3530 END_TEST
3531
3532 /* Test trailing right square bracket in an external entity parse */
START_TEST(test_ext_entity_trailing_rsqb)3533 START_TEST(test_ext_entity_trailing_rsqb) {
3534 const char *text = "<!DOCTYPE doc [\n"
3535 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3536 "]>\n"
3537 "<doc>&en;</doc>";
3538 int found_rsqb;
3539
3540 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3541 XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher);
3542 XML_SetUserData(g_parser, &found_rsqb);
3543 found_rsqb = 0;
3544 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3545 != XML_STATUS_OK)
3546 xml_failure(g_parser);
3547 if (found_rsqb == 0)
3548 fail("No right square bracket found");
3549 }
3550 END_TEST
3551
3552 /* Test CDATA handling in an external entity */
START_TEST(test_ext_entity_good_cdata)3553 START_TEST(test_ext_entity_good_cdata) {
3554 const char *text = "<!DOCTYPE doc [\n"
3555 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3556 "]>\n"
3557 "<doc>&en;</doc>";
3558
3559 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3560 XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii);
3561 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3562 != XML_STATUS_OK)
3563 xml_failure(g_parser);
3564 }
3565 END_TEST
3566
3567 /* Test user parameter settings */
START_TEST(test_user_parameters)3568 START_TEST(test_user_parameters) {
3569 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3570 "<!-- Primary parse -->\n"
3571 "<!DOCTYPE doc SYSTEM 'foo'>\n"
3572 "<doc>&entity;";
3573 const char *epilog = "<!-- Back to primary parser -->\n"
3574 "</doc>";
3575
3576 g_comment_count = 0;
3577 g_skip_count = 0;
3578 g_xdecl_count = 0;
3579 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3580 XML_SetXmlDeclHandler(g_parser, xml_decl_handler);
3581 XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker);
3582 XML_SetCommentHandler(g_parser, data_check_comment_handler);
3583 XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler);
3584 XML_UseParserAsHandlerArg(g_parser);
3585 XML_SetUserData(g_parser, (void *)1);
3586 g_handler_data = g_parser;
3587 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
3588 == XML_STATUS_ERROR)
3589 xml_failure(g_parser);
3590 /* Ensure we can't change policy mid-parse */
3591 if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER))
3592 fail("Changed param entity parsing policy while parsing");
3593 if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
3594 == XML_STATUS_ERROR)
3595 xml_failure(g_parser);
3596 if (g_comment_count != 3)
3597 fail("Comment handler not invoked enough times");
3598 if (g_skip_count != 1)
3599 fail("Skip handler not invoked enough times");
3600 if (g_xdecl_count != 1)
3601 fail("XML declaration handler not invoked");
3602 }
3603 END_TEST
3604
3605 /* Test that an explicit external entity handler argument replaces
3606 * the parser as the first argument.
3607 *
3608 * We do not call the first parameter to the external entity handler
3609 * 'parser' for once, since the first time the handler is called it
3610 * will actually be a text string. We need to be able to access the
3611 * global 'parser' variable to create our external entity parser from,
3612 * since there are code paths we need to ensure get executed.
3613 */
START_TEST(test_ext_entity_ref_parameter)3614 START_TEST(test_ext_entity_ref_parameter) {
3615 const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3616 "<!DOCTYPE doc SYSTEM 'foo'>\n"
3617 "<doc>&entity;</doc>";
3618
3619 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3620 XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
3621 /* Set a handler arg that is not NULL and not parser (which is
3622 * what NULL would cause to be passed.
3623 */
3624 XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text);
3625 g_handler_data = text;
3626 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3627 == XML_STATUS_ERROR)
3628 xml_failure(g_parser);
3629
3630 /* Now try again with unset args */
3631 XML_ParserReset(g_parser, NULL);
3632 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3633 XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
3634 XML_SetExternalEntityRefHandlerArg(g_parser, NULL);
3635 g_handler_data = g_parser;
3636 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3637 == XML_STATUS_ERROR)
3638 xml_failure(g_parser);
3639 }
3640 END_TEST
3641
3642 /* Test the parsing of an empty string */
START_TEST(test_empty_parse)3643 START_TEST(test_empty_parse) {
3644 const char *text = "<doc></doc>";
3645 const char *partial = "<doc>";
3646
3647 if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
3648 fail("Parsing empty string faulted");
3649 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
3650 fail("Parsing final empty string not faulted");
3651 if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS)
3652 fail("Parsing final empty string faulted for wrong reason");
3653
3654 /* Now try with valid text before the empty end */
3655 XML_ParserReset(g_parser, NULL);
3656 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
3657 == XML_STATUS_ERROR)
3658 xml_failure(g_parser);
3659 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
3660 fail("Parsing final empty string faulted");
3661
3662 /* Now try with invalid text before the empty end */
3663 XML_ParserReset(g_parser, NULL);
3664 if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial),
3665 XML_FALSE)
3666 == XML_STATUS_ERROR)
3667 xml_failure(g_parser);
3668 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
3669 fail("Parsing final incomplete empty string not faulted");
3670 }
3671 END_TEST
3672
3673 /* Test XML_Parse for len < 0 */
START_TEST(test_negative_len_parse)3674 START_TEST(test_negative_len_parse) {
3675 const char *const doc = "<root/>";
3676 for (int isFinal = 0; isFinal < 2; isFinal++) {
3677 set_subtest("isFinal=%d", isFinal);
3678
3679 XML_Parser parser = XML_ParserCreate(NULL);
3680
3681 if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
3682 fail("There was not supposed to be any initial parse error.");
3683
3684 const enum XML_Status status = XML_Parse(parser, doc, -1, isFinal);
3685
3686 if (status != XML_STATUS_ERROR)
3687 fail("Negative len was expected to fail the parse but did not.");
3688
3689 if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_ARGUMENT)
3690 fail("Parse error does not match XML_ERROR_INVALID_ARGUMENT.");
3691
3692 XML_ParserFree(parser);
3693 }
3694 }
3695 END_TEST
3696
3697 /* Test XML_ParseBuffer for len < 0 */
START_TEST(test_negative_len_parse_buffer)3698 START_TEST(test_negative_len_parse_buffer) {
3699 const char *const doc = "<root/>";
3700 for (int isFinal = 0; isFinal < 2; isFinal++) {
3701 set_subtest("isFinal=%d", isFinal);
3702
3703 XML_Parser parser = XML_ParserCreate(NULL);
3704
3705 if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
3706 fail("There was not supposed to be any initial parse error.");
3707
3708 void *const buffer = XML_GetBuffer(parser, (int)strlen(doc));
3709
3710 if (buffer == NULL)
3711 fail("XML_GetBuffer failed.");
3712
3713 memcpy(buffer, doc, strlen(doc));
3714
3715 const enum XML_Status status = XML_ParseBuffer(parser, -1, isFinal);
3716
3717 if (status != XML_STATUS_ERROR)
3718 fail("Negative len was expected to fail the parse but did not.");
3719
3720 if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_ARGUMENT)
3721 fail("Parse error does not match XML_ERROR_INVALID_ARGUMENT.");
3722
3723 XML_ParserFree(parser);
3724 }
3725 }
3726 END_TEST
3727
3728 /* Test odd corners of the XML_GetBuffer interface */
3729 static enum XML_Status
get_feature(enum XML_FeatureEnum feature_id,long * presult)3730 get_feature(enum XML_FeatureEnum feature_id, long *presult) {
3731 const XML_Feature *feature = XML_GetFeatureList();
3732
3733 if (feature == NULL)
3734 return XML_STATUS_ERROR;
3735 for (; feature->feature != XML_FEATURE_END; feature++) {
3736 if (feature->feature == feature_id) {
3737 *presult = feature->value;
3738 return XML_STATUS_OK;
3739 }
3740 }
3741 return XML_STATUS_ERROR;
3742 }
3743
3744 /* Test odd corners of the XML_GetBuffer interface */
START_TEST(test_get_buffer_1)3745 START_TEST(test_get_buffer_1) {
3746 const char *text = get_buffer_test_text;
3747 long context_bytes;
3748
3749 /* Attempt to allocate a negative length buffer */
3750 if (XML_GetBuffer(g_parser, -12) != NULL)
3751 fail("Negative length buffer not failed");
3752
3753 /* Now get a small buffer and extend it past valid length */
3754 void *const buffer = XML_GetBuffer(g_parser, 1536);
3755 if (buffer == NULL)
3756 fail("1.5K buffer failed");
3757 assert(buffer != NULL);
3758 memcpy(buffer, text, strlen(text));
3759 if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
3760 == XML_STATUS_ERROR)
3761 xml_failure(g_parser);
3762 if (XML_GetBuffer(g_parser, INT_MAX) != NULL)
3763 fail("INT_MAX buffer not failed");
3764
3765 /* Now try extending it a more reasonable but still too large
3766 * amount. The allocator in XML_GetBuffer() doubles the buffer
3767 * size until it exceeds the requested amount or INT_MAX. If it
3768 * exceeds INT_MAX, it rejects the request, so we want a request
3769 * between INT_MAX and INT_MAX/2. A gap of 1K seems comfortable,
3770 * with an extra byte just to ensure that the request is off any
3771 * boundary. The request will be inflated internally by
3772 * XML_CONTEXT_BYTES (if >=1), so we subtract that from our
3773 * request.
3774 */
3775 if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK)
3776 context_bytes = 0;
3777 if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL)
3778 fail("INT_MAX- buffer not failed");
3779
3780 /* Now try extending it a carefully crafted amount */
3781 if (XML_GetBuffer(g_parser, 1000) == NULL)
3782 fail("1000 buffer failed");
3783 }
3784 END_TEST
3785
3786 /* Test more corners of the XML_GetBuffer interface */
START_TEST(test_get_buffer_2)3787 START_TEST(test_get_buffer_2) {
3788 const char *text = get_buffer_test_text;
3789
3790 /* Now get a decent buffer */
3791 void *const buffer = XML_GetBuffer(g_parser, 1536);
3792 if (buffer == NULL)
3793 fail("1.5K buffer failed");
3794 assert(buffer != NULL);
3795 memcpy(buffer, text, strlen(text));
3796 if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
3797 == XML_STATUS_ERROR)
3798 xml_failure(g_parser);
3799
3800 /* Extend it, to catch a different code path */
3801 if (XML_GetBuffer(g_parser, 1024) == NULL)
3802 fail("1024 buffer failed");
3803 }
3804 END_TEST
3805
3806 /* Test for signed integer overflow CVE-2022-23852 */
3807 #if XML_CONTEXT_BYTES > 0
START_TEST(test_get_buffer_3_overflow)3808 START_TEST(test_get_buffer_3_overflow) {
3809 XML_Parser parser = XML_ParserCreate(NULL);
3810 assert(parser != NULL);
3811
3812 const char *const text = "\n";
3813 const int expectedKeepValue = (int)strlen(text);
3814
3815 // After this call, variable "keep" in XML_GetBuffer will
3816 // have value expectedKeepValue
3817 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text),
3818 XML_FALSE /* isFinal */)
3819 == XML_STATUS_ERROR)
3820 xml_failure(parser);
3821
3822 assert(expectedKeepValue > 0);
3823 if (XML_GetBuffer(parser, INT_MAX - expectedKeepValue + 1) != NULL)
3824 fail("enlarging buffer not failed");
3825
3826 XML_ParserFree(parser);
3827 }
3828 END_TEST
3829 #endif // XML_CONTEXT_BYTES > 0
3830
START_TEST(test_buffer_can_grow_to_max)3831 START_TEST(test_buffer_can_grow_to_max) {
3832 const char *const prefixes[] = {
3833 "",
3834 "<",
3835 "<x a='",
3836 "<doc><x a='",
3837 "<document><x a='",
3838 "<averylongelementnamesuchthatitwillhopefullystretchacrossmultiplelinesand"
3839 "lookprettyridiculousitsalsoveryhardtoreadandifyouredoingitihavetowonderif"
3840 "youreallydonthaveanythingbettertodoofcourseiguessicouldveputsomethingbadin"
3841 "herebutipromisethatididntheybtwhowgreatarespacesandpunctuationforhelping"
3842 "withreadabilityprettygreatithinkanywaysthisisprobablylongenoughbye><x a='"};
3843 const int num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]);
3844 int maxbuf = INT_MAX / 2 + (INT_MAX & 1); // round up without overflow
3845 #if defined(__MINGW32__) && ! defined(__MINGW64__)
3846 // workaround for mingw/wine32 on GitHub CI not being able to reach 1GiB
3847 // Can we make a big allocation?
3848 for (int i = 1; i <= 2; i++) {
3849 void *const big = malloc(maxbuf);
3850 if (big != NULL) {
3851 free(big);
3852 break;
3853 }
3854 // The big allocation failed. Let's be a little lenient.
3855 maxbuf = maxbuf / 2;
3856 fprintf(stderr, "Reducing maxbuf to %d...\n", maxbuf);
3857 }
3858 #else
3859 UNUSED_P(maxbuf);
3860 #endif
3861
3862 for (int i = 0; i < num_prefixes; ++i) {
3863 set_subtest("\"%s\"", prefixes[i]);
3864 XML_Parser parser = XML_ParserCreate(NULL);
3865 #if XML_GE == 1
3866 assert_true(XML_SetAllocTrackerActivationThreshold(parser, (size_t)-1)
3867 == XML_TRUE); // i.e. deactivate
3868 #endif
3869 const int prefix_len = (int)strlen(prefixes[i]);
3870 const enum XML_Status s
3871 = _XML_Parse_SINGLE_BYTES(parser, prefixes[i], prefix_len, XML_FALSE);
3872 if (s != XML_STATUS_OK)
3873 xml_failure(parser);
3874
3875 // Avoid running into "AddressSanitizer: out of memory" on 32bit Windows
3876 #if ! defined(_WIN32) || EXPAT_TESTS_ASAN == 0 || EXPAT_TESTS_64BIT == 1
3877 // XML_CONTEXT_BYTES of the prefix may remain in the buffer;
3878 // subtracting the whole prefix is easiest, and close enough.
3879 assert_true(XML_GetBuffer(parser, maxbuf - prefix_len) != NULL);
3880 // The limit should be consistent; no prefix should allow us to
3881 // reach above the max buffer size.
3882 assert_true(XML_GetBuffer(parser, maxbuf + 1) == NULL);
3883 #else
3884 UNUSED_P(maxbuf);
3885 #endif
3886
3887 XML_ParserFree(parser);
3888 }
3889 }
3890 END_TEST
3891
START_TEST(test_getbuffer_allocates_on_zero_len)3892 START_TEST(test_getbuffer_allocates_on_zero_len) {
3893 for (int first_len = 1; first_len >= 0; first_len--) {
3894 set_subtest("with len=%d first", first_len);
3895 XML_Parser parser = XML_ParserCreate(NULL);
3896 assert_true(parser != NULL);
3897 assert_true(XML_GetBuffer(parser, first_len) != NULL);
3898 assert_true(XML_GetBuffer(parser, 0) != NULL);
3899 if (XML_ParseBuffer(parser, 0, XML_FALSE) != XML_STATUS_OK)
3900 xml_failure(parser);
3901 XML_ParserFree(parser);
3902 }
3903 }
3904 END_TEST
3905
3906 /* Test position information macros */
START_TEST(test_byte_info_at_end)3907 START_TEST(test_byte_info_at_end) {
3908 const char *text = "<doc></doc>";
3909
3910 if (XML_GetCurrentByteIndex(g_parser) != -1
3911 || XML_GetCurrentByteCount(g_parser) != 0)
3912 fail("Byte index/count incorrect at start of parse");
3913 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3914 == XML_STATUS_ERROR)
3915 xml_failure(g_parser);
3916 /* At end, the count will be zero and the index the end of string */
3917 if (XML_GetCurrentByteCount(g_parser) != 0)
3918 fail("Terminal byte count incorrect");
3919 if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
3920 fail("Terminal byte index incorrect");
3921 }
3922 END_TEST
3923
3924 /* Test position information from errors */
3925 #define PRE_ERROR_STR "<doc></"
3926 #define POST_ERROR_STR "wombat></doc>"
START_TEST(test_byte_info_at_error)3927 START_TEST(test_byte_info_at_error) {
3928 const char *text = PRE_ERROR_STR POST_ERROR_STR;
3929
3930 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3931 == XML_STATUS_OK)
3932 fail("Syntax error not faulted");
3933 if (XML_GetCurrentByteCount(g_parser) != 0)
3934 fail("Error byte count incorrect");
3935 if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
3936 fail("Error byte index incorrect");
3937 }
3938 END_TEST
3939 #undef PRE_ERROR_STR
3940 #undef POST_ERROR_STR
3941
3942 /* Test position information in handler */
3943 #define START_ELEMENT "<e>"
3944 #define CDATA_TEXT "Hello"
3945 #define END_ELEMENT "</e>"
START_TEST(test_byte_info_at_cdata)3946 START_TEST(test_byte_info_at_cdata) {
3947 const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
3948 int offset, size;
3949 ByteTestData data;
3950
3951 /* Check initial context is empty */
3952 if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
3953 fail("Unexpected context at start of parse");
3954
3955 data.start_element_len = (int)strlen(START_ELEMENT);
3956 data.cdata_len = (int)strlen(CDATA_TEXT);
3957 data.total_string_len = (int)strlen(text);
3958 XML_SetCharacterDataHandler(g_parser, byte_character_handler);
3959 XML_SetUserData(g_parser, &data);
3960 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
3961 xml_failure(g_parser);
3962 }
3963 END_TEST
3964 #undef START_ELEMENT
3965 #undef CDATA_TEXT
3966 #undef END_ELEMENT
3967
3968 /* Test predefined entities are correctly recognised */
START_TEST(test_predefined_entities)3969 START_TEST(test_predefined_entities) {
3970 const char *text = "<doc><>&"'</doc>";
3971 const XML_Char *expected = XCS("<doc><>&"'</doc>");
3972 const XML_Char *result = XCS("<>&\"'");
3973 CharData storage;
3974
3975 XML_SetDefaultHandler(g_parser, accumulate_characters);
3976 /* run_character_check uses XML_SetCharacterDataHandler(), which
3977 * unfortunately heads off a code path that we need to exercise.
3978 */
3979 CharData_Init(&storage);
3980 XML_SetUserData(g_parser, &storage);
3981 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3982 == XML_STATUS_ERROR)
3983 xml_failure(g_parser);
3984 /* The default handler doesn't translate the entities */
3985 CharData_CheckXMLChars(&storage, expected);
3986
3987 /* Now try again and check the translation */
3988 XML_ParserReset(g_parser, NULL);
3989 run_character_check(text, result);
3990 }
3991 END_TEST
3992
3993 /* Regression test that an invalid tag in an external parameter
3994 * reference in an external DTD is correctly faulted.
3995 *
3996 * Only a few specific tags are legal in DTDs ignoring comments and
3997 * processing instructions, all of which begin with an exclamation
3998 * mark. "<el/>" is not one of them, so the parser should raise an
3999 * error on encountering it.
4000 */
START_TEST(test_invalid_tag_in_dtd)4001 START_TEST(test_invalid_tag_in_dtd) {
4002 const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4003 "<doc></doc>\n";
4004
4005 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4006 XML_SetExternalEntityRefHandler(g_parser, external_entity_param);
4007 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4008 "Invalid tag IN DTD external param not rejected");
4009 }
4010 END_TEST
4011
4012 /* Test entities not quite the predefined ones are not mis-recognised */
START_TEST(test_not_predefined_entities)4013 START_TEST(test_not_predefined_entities) {
4014 const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>",
4015 "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL};
4016 int i = 0;
4017
4018 while (text[i] != NULL) {
4019 expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY,
4020 "Undefined entity not rejected");
4021 XML_ParserReset(g_parser, NULL);
4022 i++;
4023 }
4024 }
4025 END_TEST
4026
4027 /* Test conditional inclusion (IGNORE) */
START_TEST(test_ignore_section)4028 START_TEST(test_ignore_section) {
4029 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4030 "<doc><e>&entity;</e></doc>";
4031 const XML_Char *expected
4032 = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;");
4033 CharData storage;
4034
4035 CharData_Init(&storage);
4036 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4037 XML_SetUserData(g_parser, &storage);
4038 XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore);
4039 XML_SetDefaultHandler(g_parser, accumulate_characters);
4040 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4041 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4042 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4043 XML_SetStartElementHandler(g_parser, dummy_start_element);
4044 XML_SetEndElementHandler(g_parser, dummy_end_element);
4045 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4046 == XML_STATUS_ERROR)
4047 xml_failure(g_parser);
4048 CharData_CheckXMLChars(&storage, expected);
4049 }
4050 END_TEST
4051
START_TEST(test_ignore_section_utf16)4052 START_TEST(test_ignore_section_utf16) {
4053 const char text[] =
4054 /* <!DOCTYPE d SYSTEM 's'> */
4055 "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
4056 "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0"
4057 /* <d><e>&en;</e></d> */
4058 "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0";
4059 const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
4060 CharData storage;
4061
4062 CharData_Init(&storage);
4063 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4064 XML_SetUserData(g_parser, &storage);
4065 XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16);
4066 XML_SetDefaultHandler(g_parser, accumulate_characters);
4067 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4068 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4069 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4070 XML_SetStartElementHandler(g_parser, dummy_start_element);
4071 XML_SetEndElementHandler(g_parser, dummy_end_element);
4072 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4073 == XML_STATUS_ERROR)
4074 xml_failure(g_parser);
4075 CharData_CheckXMLChars(&storage, expected);
4076 }
4077 END_TEST
4078
START_TEST(test_ignore_section_utf16_be)4079 START_TEST(test_ignore_section_utf16_be) {
4080 const char text[] =
4081 /* <!DOCTYPE d SYSTEM 's'> */
4082 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
4083 "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n"
4084 /* <d><e>&en;</e></d> */
4085 "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>";
4086 const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
4087 CharData storage;
4088
4089 CharData_Init(&storage);
4090 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4091 XML_SetUserData(g_parser, &storage);
4092 XML_SetExternalEntityRefHandler(g_parser,
4093 external_entity_load_ignore_utf16_be);
4094 XML_SetDefaultHandler(g_parser, accumulate_characters);
4095 XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4096 XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4097 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4098 XML_SetStartElementHandler(g_parser, dummy_start_element);
4099 XML_SetEndElementHandler(g_parser, dummy_end_element);
4100 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4101 == XML_STATUS_ERROR)
4102 xml_failure(g_parser);
4103 CharData_CheckXMLChars(&storage, expected);
4104 }
4105 END_TEST
4106
4107 /* Test mis-formatted conditional exclusion */
START_TEST(test_bad_ignore_section)4108 START_TEST(test_bad_ignore_section) {
4109 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4110 "<doc><e>&entity;</e></doc>";
4111 ExtFaults faults[]
4112 = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL,
4113 XML_ERROR_SYNTAX},
4114 {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL,
4115 XML_ERROR_INVALID_TOKEN},
4116 {/* FIrst two bytes of a three-byte char */
4117 "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL,
4118 XML_ERROR_PARTIAL_CHAR},
4119 {NULL, NULL, NULL, XML_ERROR_NONE}};
4120 ExtFaults *fault;
4121
4122 for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
4123 set_subtest("%s", fault->parse_text);
4124 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4125 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
4126 XML_SetUserData(g_parser, fault);
4127 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4128 "Incomplete IGNORE section not failed");
4129 XML_ParserReset(g_parser, NULL);
4130 }
4131 }
4132 END_TEST
4133
4134 struct bom_testdata {
4135 const char *external;
4136 int split;
4137 XML_Bool nested_callback_happened;
4138 };
4139
4140 static int XMLCALL
external_bom_checker(XML_Parser parser,const XML_Char * context,const XML_Char * base,const XML_Char * systemId,const XML_Char * publicId)4141 external_bom_checker(XML_Parser parser, const XML_Char *context,
4142 const XML_Char *base, const XML_Char *systemId,
4143 const XML_Char *publicId) {
4144 const char *text;
4145 UNUSED_P(base);
4146 UNUSED_P(systemId);
4147 UNUSED_P(publicId);
4148
4149 XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4150 if (ext_parser == NULL)
4151 fail("Could not create external entity parser");
4152
4153 if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4154 struct bom_testdata *const testdata = XML_GetUserData(parser);
4155 const char *const external = testdata->external;
4156 const int split = testdata->split;
4157 testdata->nested_callback_happened = XML_TRUE;
4158
4159 if (_XML_Parse_SINGLE_BYTES(ext_parser, external, split, XML_FALSE)
4160 != XML_STATUS_OK) {
4161 xml_failure(ext_parser);
4162 }
4163 text = external + split; // the parse below will continue where we left off.
4164 } else if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4165 text = "<!ELEMENT doc EMPTY>\n"
4166 "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
4167 "<!ENTITY % e2 '%e1;'>\n";
4168 } else {
4169 fail("unknown systemId");
4170 }
4171
4172 if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
4173 != XML_STATUS_OK)
4174 xml_failure(ext_parser);
4175
4176 XML_ParserFree(ext_parser);
4177 return XML_STATUS_OK;
4178 }
4179
4180 /* regression test: BOM should be consumed when followed by a partial token. */
START_TEST(test_external_bom_consumed)4181 START_TEST(test_external_bom_consumed) {
4182 const char *const text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4183 "<doc></doc>\n";
4184 const char *const external = "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>";
4185 const int len = (int)strlen(external);
4186 for (int split = 0; split <= len; ++split) {
4187 set_subtest("split at byte %d", split);
4188
4189 struct bom_testdata testdata;
4190 testdata.external = external;
4191 testdata.split = split;
4192 testdata.nested_callback_happened = XML_FALSE;
4193
4194 XML_Parser parser = XML_ParserCreate(NULL);
4195 if (parser == NULL) {
4196 fail("Couldn't create parser");
4197 }
4198 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4199 XML_SetExternalEntityRefHandler(parser, external_bom_checker);
4200 XML_SetUserData(parser, &testdata);
4201 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
4202 == XML_STATUS_ERROR)
4203 xml_failure(parser);
4204 if (! testdata.nested_callback_happened) {
4205 fail("ref handler not called");
4206 }
4207 XML_ParserFree(parser);
4208 }
4209 }
4210 END_TEST
4211
4212 /* Test recursive parsing */
START_TEST(test_external_entity_values)4213 START_TEST(test_external_entity_values) {
4214 const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4215 "<doc></doc>\n";
4216 ExtFaults data_004_2[] = {
4217 {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE},
4218 {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL,
4219 XML_ERROR_INVALID_TOKEN},
4220 {"'wombat", "Unterminated string not faulted", NULL,
4221 XML_ERROR_UNCLOSED_TOKEN},
4222 {"\xe2\x82", "Partial UTF-8 character not faulted", NULL,
4223 XML_ERROR_PARTIAL_CHAR},
4224 {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE},
4225 {"<?xml?>", "Malformed XML declaration not faulted", NULL,
4226 XML_ERROR_XML_DECL},
4227 {/* UTF-8 BOM */
4228 "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL,
4229 XML_ERROR_NONE},
4230 {"<?xml version='1.0' encoding='utf-8'?>\n$",
4231 "Invalid token after text declaration not faulted", NULL,
4232 XML_ERROR_INVALID_TOKEN},
4233 {"<?xml version='1.0' encoding='utf-8'?>\n'wombat",
4234 "Unterminated string after text decl not faulted", NULL,
4235 XML_ERROR_UNCLOSED_TOKEN},
4236 {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82",
4237 "Partial UTF-8 character after text decl not faulted", NULL,
4238 XML_ERROR_PARTIAL_CHAR},
4239 {"%e1;", "Recursive parameter entity not faulted", NULL,
4240 XML_ERROR_RECURSIVE_ENTITY_REF},
4241 {NULL, NULL, NULL, XML_ERROR_NONE}};
4242 int i;
4243
4244 for (i = 0; data_004_2[i].parse_text != NULL; i++) {
4245 set_subtest("%s", data_004_2[i].parse_text);
4246 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4247 XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer);
4248 XML_SetUserData(g_parser, &data_004_2[i]);
4249 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4250 == XML_STATUS_ERROR)
4251 xml_failure(g_parser);
4252 XML_ParserReset(g_parser, NULL);
4253 }
4254 }
4255 END_TEST
4256
4257 /* Test the recursive parse interacts with a not standalone handler */
START_TEST(test_ext_entity_not_standalone)4258 START_TEST(test_ext_entity_not_standalone) {
4259 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4260 "<doc></doc>";
4261
4262 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4263 XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone);
4264 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4265 "Standalone rejection not caught");
4266 }
4267 END_TEST
4268
START_TEST(test_ext_entity_value_abort)4269 START_TEST(test_ext_entity_value_abort) {
4270 const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4271 "<doc></doc>\n";
4272
4273 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4274 XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter);
4275 g_resumable = XML_FALSE;
4276 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4277 == XML_STATUS_ERROR)
4278 xml_failure(g_parser);
4279 }
4280 END_TEST
4281
START_TEST(test_bad_public_doctype)4282 START_TEST(test_bad_public_doctype) {
4283 const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
4284 "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n"
4285 "<doc></doc>";
4286
4287 /* Setting a handler provokes a particular code path */
4288 XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
4289 dummy_end_doctype_handler);
4290 expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed");
4291 }
4292 END_TEST
4293
4294 /* Test based on ibm/valid/P32/ibm32v04.xml */
START_TEST(test_attribute_enum_value)4295 START_TEST(test_attribute_enum_value) {
4296 const char *text = "<?xml version='1.0' standalone='no'?>\n"
4297 "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
4298 "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
4299 ExtTest dtd_data
4300 = {"<!ELEMENT animal (#PCDATA|a)*>\n"
4301 "<!ELEMENT a EMPTY>\n"
4302 "<!ATTLIST animal xml:space (default|preserve) 'preserve'>",
4303 NULL, NULL};
4304 const XML_Char *expected = XCS("This is a \n \n\nyellow tiger");
4305
4306 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4307 XML_SetUserData(g_parser, &dtd_data);
4308 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4309 /* An attribute list handler provokes a different code path */
4310 XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
4311 run_ext_character_check(text, &dtd_data, expected);
4312 }
4313 END_TEST
4314
4315 /* Slightly bizarrely, the library seems to silently ignore entity
4316 * definitions for predefined entities, even when they are wrong. The
4317 * language of the XML 1.0 spec is somewhat unhelpful as to what ought
4318 * to happen, so this is currently treated as acceptable.
4319 */
START_TEST(test_predefined_entity_redefinition)4320 START_TEST(test_predefined_entity_redefinition) {
4321 const char *text = "<!DOCTYPE doc [\n"
4322 "<!ENTITY apos 'foo'>\n"
4323 "]>\n"
4324 "<doc>'</doc>";
4325 run_character_check(text, XCS("'"));
4326 }
4327 END_TEST
4328
4329 /* Test that the parser stops processing the DTD after an unresolved
4330 * parameter entity is encountered.
4331 */
START_TEST(test_dtd_stop_processing)4332 START_TEST(test_dtd_stop_processing) {
4333 const char *text = "<!DOCTYPE doc [\n"
4334 "%foo;\n"
4335 "<!ENTITY bar 'bas'>\n"
4336 "]><doc/>";
4337
4338 XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
4339 init_dummy_handlers();
4340 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4341 == XML_STATUS_ERROR)
4342 xml_failure(g_parser);
4343 if (get_dummy_handler_flags() != 0)
4344 fail("DTD processing still going after undefined PE");
4345 }
4346 END_TEST
4347
4348 /* Test public notations with no system ID */
START_TEST(test_public_notation_no_sysid)4349 START_TEST(test_public_notation_no_sysid) {
4350 const char *text = "<!DOCTYPE doc [\n"
4351 "<!NOTATION note PUBLIC 'foo'>\n"
4352 "<!ELEMENT doc EMPTY>\n"
4353 "]>\n<doc/>";
4354
4355 init_dummy_handlers();
4356 XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
4357 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4358 == XML_STATUS_ERROR)
4359 xml_failure(g_parser);
4360 if (get_dummy_handler_flags() != DUMMY_NOTATION_DECL_HANDLER_FLAG)
4361 fail("Notation declaration handler not called");
4362 }
4363 END_TEST
4364
START_TEST(test_nested_groups)4365 START_TEST(test_nested_groups) {
4366 const char *text
4367 = "<!DOCTYPE doc [\n"
4368 "<!ELEMENT doc "
4369 /* Sixteen elements per line */
4370 "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
4371 "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
4372 "))))))))))))))))))))))))))))))))>\n"
4373 "<!ELEMENT e EMPTY>"
4374 "]>\n"
4375 "<doc><e/></doc>";
4376 CharData storage;
4377
4378 CharData_Init(&storage);
4379 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4380 XML_SetStartElementHandler(g_parser, record_element_start_handler);
4381 XML_SetUserData(g_parser, &storage);
4382 init_dummy_handlers();
4383 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4384 == XML_STATUS_ERROR)
4385 xml_failure(g_parser);
4386 CharData_CheckXMLChars(&storage, XCS("doce"));
4387 if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
4388 fail("Element handler not fired");
4389 }
4390 END_TEST
4391
START_TEST(test_group_choice)4392 START_TEST(test_group_choice) {
4393 const char *text = "<!DOCTYPE doc [\n"
4394 "<!ELEMENT doc (a|b|c)+>\n"
4395 "<!ELEMENT a EMPTY>\n"
4396 "<!ELEMENT b (#PCDATA)>\n"
4397 "<!ELEMENT c ANY>\n"
4398 "]>\n"
4399 "<doc>\n"
4400 "<a/>\n"
4401 "<b attr='foo'>This is a foo</b>\n"
4402 "<c></c>\n"
4403 "</doc>\n";
4404
4405 XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4406 init_dummy_handlers();
4407 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4408 == XML_STATUS_ERROR)
4409 xml_failure(g_parser);
4410 if (get_dummy_handler_flags() != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
4411 fail("Element handler flag not raised");
4412 }
4413 END_TEST
4414
START_TEST(test_standalone_parameter_entity)4415 START_TEST(test_standalone_parameter_entity) {
4416 const char *text = "<?xml version='1.0' standalone='yes'?>\n"
4417 "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n"
4418 "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n"
4419 "%entity;\n"
4420 "]>\n"
4421 "<doc></doc>";
4422 char dtd_data[] = "<!ENTITY % e1 'foo'>\n";
4423
4424 XML_SetUserData(g_parser, dtd_data);
4425 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4426 XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
4427 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4428 == XML_STATUS_ERROR)
4429 xml_failure(g_parser);
4430 }
4431 END_TEST
4432
4433 /* Test skipping of parameter entity in an external DTD */
4434 /* Derived from ibm/invalid/P69/ibm69i01.xml */
START_TEST(test_skipped_parameter_entity)4435 START_TEST(test_skipped_parameter_entity) {
4436 const char *text = "<?xml version='1.0'?>\n"
4437 "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
4438 "<!ELEMENT root (#PCDATA|a)* >\n"
4439 "]>\n"
4440 "<root></root>";
4441 ExtTest dtd_data = {"%pe2;", NULL, NULL};
4442
4443 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4444 XML_SetUserData(g_parser, &dtd_data);
4445 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4446 XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler);
4447 init_dummy_handlers();
4448 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4449 == XML_STATUS_ERROR)
4450 xml_failure(g_parser);
4451 if (get_dummy_handler_flags() != DUMMY_SKIP_HANDLER_FLAG)
4452 fail("Skip handler not executed");
4453 }
4454 END_TEST
4455
4456 /* Test recursive parameter entity definition rejected in external DTD */
START_TEST(test_recursive_external_parameter_entity)4457 START_TEST(test_recursive_external_parameter_entity) {
4458 const char *text = "<?xml version='1.0'?>\n"
4459 "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
4460 "<!ELEMENT root (#PCDATA|a)* >\n"
4461 "]>\n"
4462 "<root></root>";
4463 ExtFaults dtd_data = {"<!ENTITY % pe2 '%pe2;'>\n%pe2;",
4464 "Recursive external parameter entity not faulted", NULL,
4465 XML_ERROR_RECURSIVE_ENTITY_REF};
4466
4467 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
4468 XML_SetUserData(g_parser, &dtd_data);
4469 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4470 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4471 "Recursive external parameter not spotted");
4472 }
4473 END_TEST
4474
4475 /* Test undefined parameter entity in external entity handler */
START_TEST(test_undefined_ext_entity_in_external_dtd)4476 START_TEST(test_undefined_ext_entity_in_external_dtd) {
4477 const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4478 "<doc></doc>\n";
4479
4480 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4481 XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
4482 XML_SetUserData(g_parser, NULL);
4483 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4484 == XML_STATUS_ERROR)
4485 xml_failure(g_parser);
4486
4487 /* Now repeat without the external entity ref handler invoking
4488 * another copy of itself.
4489 */
4490 XML_ParserReset(g_parser, NULL);
4491 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4492 XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
4493 XML_SetUserData(g_parser, g_parser); /* Any non-NULL value will do */
4494 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4495 == XML_STATUS_ERROR)
4496 xml_failure(g_parser);
4497 }
4498 END_TEST
4499
4500 /* Test suspending the parse on receiving an XML declaration works */
START_TEST(test_suspend_xdecl)4501 START_TEST(test_suspend_xdecl) {
4502 const char *text = long_character_data_text;
4503
4504 XML_SetXmlDeclHandler(g_parser, entity_suspending_xdecl_handler);
4505 XML_SetUserData(g_parser, g_parser);
4506 g_resumable = XML_TRUE;
4507 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
4508 // we won't know exactly how much input we actually managed to give Expat.
4509 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4510 != XML_STATUS_SUSPENDED)
4511 xml_failure(g_parser);
4512 if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
4513 xml_failure(g_parser);
4514 /* Attempt to start a new parse while suspended */
4515 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4516 != XML_STATUS_ERROR)
4517 fail("Attempt to parse while suspended not faulted");
4518 if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
4519 fail("Suspended parse not faulted with correct error");
4520 }
4521 END_TEST
4522
4523 /* Test aborting the parse in an epilog works */
START_TEST(test_abort_epilog)4524 START_TEST(test_abort_epilog) {
4525 const char *text = "<doc></doc>\n\r\n";
4526 XML_Char trigger_char = XCS('\r');
4527
4528 XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4529 XML_SetUserData(g_parser, &trigger_char);
4530 g_resumable = XML_FALSE;
4531 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4532 != XML_STATUS_ERROR)
4533 fail("Abort not triggered");
4534 if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
4535 xml_failure(g_parser);
4536 }
4537 END_TEST
4538
4539 /* Test a different code path for abort in the epilog */
START_TEST(test_abort_epilog_2)4540 START_TEST(test_abort_epilog_2) {
4541 const char *text = "<doc></doc>\n";
4542 XML_Char trigger_char = XCS('\n');
4543
4544 XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4545 XML_SetUserData(g_parser, &trigger_char);
4546 g_resumable = XML_FALSE;
4547 expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered");
4548 }
4549 END_TEST
4550
4551 /* Test suspension from the epilog */
START_TEST(test_suspend_epilog)4552 START_TEST(test_suspend_epilog) {
4553 const char *text = "<doc></doc>\n";
4554 XML_Char trigger_char = XCS('\n');
4555
4556 XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4557 XML_SetUserData(g_parser, &trigger_char);
4558 g_resumable = XML_TRUE;
4559 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4560 != XML_STATUS_SUSPENDED)
4561 xml_failure(g_parser);
4562 }
4563 END_TEST
4564
START_TEST(test_suspend_in_sole_empty_tag)4565 START_TEST(test_suspend_in_sole_empty_tag) {
4566 const char *text = "<doc/>";
4567 enum XML_Status rc;
4568
4569 XML_SetEndElementHandler(g_parser, suspending_end_handler);
4570 XML_SetUserData(g_parser, g_parser);
4571 rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
4572 if (rc == XML_STATUS_ERROR)
4573 xml_failure(g_parser);
4574 else if (rc != XML_STATUS_SUSPENDED)
4575 fail("Suspend not triggered");
4576 rc = XML_ResumeParser(g_parser);
4577 if (rc == XML_STATUS_ERROR)
4578 xml_failure(g_parser);
4579 else if (rc != XML_STATUS_OK)
4580 fail("Resume failed");
4581 }
4582 END_TEST
4583
START_TEST(test_unfinished_epilog)4584 START_TEST(test_unfinished_epilog) {
4585 const char *text = "<doc></doc><";
4586
4587 expect_failure(text, XML_ERROR_UNCLOSED_TOKEN,
4588 "Incomplete epilog entry not faulted");
4589 }
4590 END_TEST
4591
START_TEST(test_partial_char_in_epilog)4592 START_TEST(test_partial_char_in_epilog) {
4593 const char *text = "<doc></doc>\xe2\x82";
4594
4595 /* First check that no fault is raised if the parse is not finished */
4596 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
4597 == XML_STATUS_ERROR)
4598 xml_failure(g_parser);
4599 /* Now check that it is faulted once we finish */
4600 if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
4601 fail("Partial character in epilog not faulted");
4602 if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR)
4603 xml_failure(g_parser);
4604 }
4605 END_TEST
4606
4607 /* Test resuming a parse suspended in entity substitution */
START_TEST(test_suspend_resume_internal_entity)4608 START_TEST(test_suspend_resume_internal_entity) {
4609 const char *text
4610 = "<!DOCTYPE doc [\n"
4611 "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n"
4612 "]>\n"
4613 "<doc>&foo;</doc>\n";
4614 const XML_Char *expected1 = XCS("Hi");
4615 const XML_Char *expected2 = XCS("HiHo");
4616 CharData storage;
4617
4618 CharData_Init(&storage);
4619 XML_SetStartElementHandler(g_parser, start_element_suspender);
4620 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
4621 XML_SetUserData(g_parser, &storage);
4622 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
4623 // we won't know exactly how much input we actually managed to give Expat.
4624 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4625 != XML_STATUS_SUSPENDED)
4626 xml_failure(g_parser);
4627 CharData_CheckXMLChars(&storage, XCS(""));
4628 if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
4629 xml_failure(g_parser);
4630 CharData_CheckXMLChars(&storage, expected1);
4631 if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
4632 xml_failure(g_parser);
4633 CharData_CheckXMLChars(&storage, expected2);
4634 }
4635 END_TEST
4636
START_TEST(test_suspend_resume_internal_entity_issue_629)4637 START_TEST(test_suspend_resume_internal_entity_issue_629) {
4638 const char *const text
4639 = "<!DOCTYPE a [<!ENTITY e '<!--COMMENT-->a'>]><a>&e;<b>\n"
4640 "<"
4641 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4642 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4643 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4644 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4645 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4646 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4647 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4648 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4649 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4650 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4651 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4652 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4653 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4654 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4655 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4656 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4657 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4658 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4659 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4660 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4661 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4662 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4663 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4664 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4665 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4666 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4667 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4668 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4669 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4670 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4671 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4672 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4673 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4674 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4675 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4676 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4677 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4678 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4679 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4680 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
4681 "/>"
4682 "</b></a>";
4683 const size_t firstChunkSizeBytes = 54;
4684
4685 XML_Parser parser = XML_ParserCreate(NULL);
4686 XML_SetUserData(parser, parser);
4687 XML_SetCommentHandler(parser, suspending_comment_handler);
4688
4689 if (XML_Parse(parser, text, (int)firstChunkSizeBytes, XML_FALSE)
4690 != XML_STATUS_SUSPENDED)
4691 xml_failure(parser);
4692 if (XML_ResumeParser(parser) != XML_STATUS_OK)
4693 xml_failure(parser);
4694 if (_XML_Parse_SINGLE_BYTES(parser, text + firstChunkSizeBytes,
4695 (int)(strlen(text) - firstChunkSizeBytes),
4696 XML_TRUE)
4697 != XML_STATUS_OK)
4698 xml_failure(parser);
4699 XML_ParserFree(parser);
4700 }
4701 END_TEST
4702
4703 /* Test syntax error is caught at parse resumption */
START_TEST(test_resume_entity_with_syntax_error)4704 START_TEST(test_resume_entity_with_syntax_error) {
4705 if (g_chunkSize != 0) {
4706 // this test does not use SINGLE_BYTES, because of suspension
4707 return;
4708 }
4709
4710 const char *text = "<!DOCTYPE doc [\n"
4711 "<!ENTITY foo '<suspend>Hi</wombat>'>\n"
4712 "]>\n"
4713 "<doc>&foo;</doc>\n";
4714
4715 XML_SetStartElementHandler(g_parser, start_element_suspender);
4716 // can't use SINGLE_BYTES here, because it'll return early on suspension, and
4717 // we won't know exactly how much input we actually managed to give Expat.
4718 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4719 != XML_STATUS_SUSPENDED)
4720 xml_failure(g_parser);
4721 if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
4722 fail("Syntax error in entity not faulted");
4723 if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH)
4724 xml_failure(g_parser);
4725 }
4726 END_TEST
4727
4728 /* Test suspending and resuming in a parameter entity substitution */
START_TEST(test_suspend_resume_parameter_entity)4729 START_TEST(test_suspend_resume_parameter_entity) {
4730 const char *text = "<!DOCTYPE doc [\n"
4731 "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n"
4732 "%foo;\n"
4733 "]>\n"
4734 "<doc>Hello, world</doc>";
4735 const XML_Char *expected = XCS("Hello, world");
4736 CharData storage;
4737
4738 CharData_Init(&storage);
4739 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4740 XML_SetElementDeclHandler(g_parser, element_decl_suspender);
4741 XML_SetCharacterDataHandler(g_parser, accumulate_characters);
4742 XML_SetUserData(g_parser, &storage);
4743 if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4744 != XML_STATUS_SUSPENDED)
4745 xml_failure(g_parser);
4746 CharData_CheckXMLChars(&storage, XCS(""));
4747 if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
4748 xml_failure(g_parser);
4749 CharData_CheckXMLChars(&storage, expected);
4750 }
4751 END_TEST
4752
4753 /* Test attempting to use parser after an error is faulted */
START_TEST(test_restart_on_error)4754 START_TEST(test_restart_on_error) {
4755 const char *text = "<$doc><doc></doc>";
4756
4757 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4758 != XML_STATUS_ERROR)
4759 fail("Invalid tag name not faulted");
4760 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
4761 xml_failure(g_parser);
4762 if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
4763 fail("Restarting invalid parse not faulted");
4764 if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
4765 xml_failure(g_parser);
4766 }
4767 END_TEST
4768
4769 /* Test that angle brackets in an attribute default value are faulted */
START_TEST(test_reject_lt_in_attribute_value)4770 START_TEST(test_reject_lt_in_attribute_value) {
4771 const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n"
4772 "<doc></doc>";
4773
4774 expect_failure(text, XML_ERROR_INVALID_TOKEN,
4775 "Bad attribute default not faulted");
4776 }
4777 END_TEST
4778
START_TEST(test_reject_unfinished_param_in_att_value)4779 START_TEST(test_reject_unfinished_param_in_att_value) {
4780 const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n"
4781 "<doc></doc>";
4782
4783 expect_failure(text, XML_ERROR_INVALID_TOKEN,
4784 "Bad attribute default not faulted");
4785 }
4786 END_TEST
4787
START_TEST(test_trailing_cr_in_att_value)4788 START_TEST(test_trailing_cr_in_att_value) {
4789 const char *text = "<doc a='value\r'/>";
4790
4791 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4792 == XML_STATUS_ERROR)
4793 xml_failure(g_parser);
4794 }
4795 END_TEST
4796
4797 /* Try parsing a general entity within a parameter entity in a
4798 * standalone internal DTD. Covers a corner case in the parser.
4799 */
START_TEST(test_standalone_internal_entity)4800 START_TEST(test_standalone_internal_entity) {
4801 const char *text = "<?xml version='1.0' standalone='yes' ?>\n"
4802 "<!DOCTYPE doc [\n"
4803 " <!ELEMENT doc (#PCDATA)>\n"
4804 " <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"≥\">'>\n"
4805 " <!ENTITY ge 'AttDefaultValue'>\n"
4806 " %pe;\n"
4807 "]>\n"
4808 "<doc att2='any'/>";
4809
4810 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4811 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4812 == XML_STATUS_ERROR)
4813 xml_failure(g_parser);
4814 }
4815 END_TEST
4816
4817 /* Test that a reference to an unknown external entity is skipped */
START_TEST(test_skipped_external_entity)4818 START_TEST(test_skipped_external_entity) {
4819 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
4820 "<doc></doc>\n";
4821 ExtTest test_data = {"<!ELEMENT doc EMPTY>\n"
4822 "<!ENTITY % e2 '%e1;'>\n",
4823 NULL, NULL};
4824
4825 XML_SetUserData(g_parser, &test_data);
4826 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4827 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4828 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4829 == XML_STATUS_ERROR)
4830 xml_failure(g_parser);
4831 }
4832 END_TEST
4833
START_TEST(test_scaff_index_shared_across_external_entity_parser)4834 START_TEST(test_scaff_index_shared_across_external_entity_parser) {
4835 const char text[]
4836 = "<!DOCTYPE doc [\n"
4837 "<!ELEMENT a "
4838 "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((b))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>\n"
4839 "<!ENTITY % e SYSTEM 'ext'>\n"
4840 "%e;\n"
4841 "<!ELEMENT c "
4842 "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((d)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>\n"
4843 "]>\n"
4844 "<doc/>";
4845 ExtOption options[]
4846 = {{XCS("ext"),
4847 "<!ELEMENT x "
4848 "((((((((((((((((((((((((((((((((y))))))))))))))))))))))))))))))))>"},
4849 {NULL, NULL}};
4850
4851 XML_Parser parser = XML_ParserCreate(NULL);
4852 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4853 XML_SetUserData(parser, options);
4854 XML_SetExternalEntityRefHandler(parser, external_entity_optioner);
4855 XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
4856
4857 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
4858 == XML_STATUS_ERROR)
4859 xml_failure(parser);
4860
4861 XML_ParserFree(parser);
4862 }
4863 END_TEST
4864
4865 /* Test a different form of unknown external entity */
START_TEST(test_skipped_null_loaded_ext_entity)4866 START_TEST(test_skipped_null_loaded_ext_entity) {
4867 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
4868 "<doc />";
4869 ExtHdlrData test_data
4870 = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
4871 "<!ENTITY % pe2 '%pe1;'>\n"
4872 "%pe2;\n",
4873 external_entity_null_loader, NULL};
4874
4875 XML_SetUserData(g_parser, &test_data);
4876 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4877 XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
4878 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4879 == XML_STATUS_ERROR)
4880 xml_failure(g_parser);
4881 }
4882 END_TEST
4883
START_TEST(test_skipped_unloaded_ext_entity)4884 START_TEST(test_skipped_unloaded_ext_entity) {
4885 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
4886 "<doc />";
4887 ExtHdlrData test_data
4888 = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
4889 "<!ENTITY % pe2 '%pe1;'>\n"
4890 "%pe2;\n",
4891 NULL, NULL};
4892
4893 XML_SetUserData(g_parser, &test_data);
4894 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4895 XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
4896 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4897 == XML_STATUS_ERROR)
4898 xml_failure(g_parser);
4899 }
4900 END_TEST
4901
4902 /* Test that a parameter entity value ending with a carriage return
4903 * has it translated internally into a newline.
4904 */
START_TEST(test_param_entity_with_trailing_cr)4905 START_TEST(test_param_entity_with_trailing_cr) {
4906 #define PARAM_ENTITY_NAME "pe"
4907 #define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">"
4908 const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
4909 "<doc/>";
4910 ExtTest test_data
4911 = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n"
4912 "%" PARAM_ENTITY_NAME ";\n",
4913 NULL, NULL};
4914
4915 XML_SetUserData(g_parser, &test_data);
4916 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4917 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4918 XML_SetEntityDeclHandler(g_parser, param_entity_match_handler);
4919 param_entity_match_init(XCS(PARAM_ENTITY_NAME),
4920 XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n"));
4921 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4922 == XML_STATUS_ERROR)
4923 xml_failure(g_parser);
4924 int entity_match_flag = get_param_entity_match_flag();
4925 if (entity_match_flag == ENTITY_MATCH_FAIL)
4926 fail("Parameter entity CR->NEWLINE conversion failed");
4927 else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND)
4928 fail("Parameter entity not parsed");
4929 }
4930 #undef PARAM_ENTITY_NAME
4931 #undef PARAM_ENTITY_CORE_VALUE
4932 END_TEST
4933
START_TEST(test_invalid_character_entity)4934 START_TEST(test_invalid_character_entity) {
4935 const char *text = "<!DOCTYPE doc [\n"
4936 " <!ENTITY entity '�'>\n"
4937 "]>\n"
4938 "<doc>&entity;</doc>";
4939
4940 expect_failure(text, XML_ERROR_BAD_CHAR_REF,
4941 "Out of range character reference not faulted");
4942 }
4943 END_TEST
4944
START_TEST(test_invalid_character_entity_2)4945 START_TEST(test_invalid_character_entity_2) {
4946 const char *text = "<!DOCTYPE doc [\n"
4947 " <!ENTITY entity '&#xg0;'>\n"
4948 "]>\n"
4949 "<doc>&entity;</doc>";
4950
4951 expect_failure(text, XML_ERROR_INVALID_TOKEN,
4952 "Out of range character reference not faulted");
4953 }
4954 END_TEST
4955
START_TEST(test_invalid_character_entity_3)4956 START_TEST(test_invalid_character_entity_3) {
4957 const char text[] =
4958 /* <!DOCTYPE doc [\n */
4959 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
4960 /* U+0E04 = KHO KHWAI
4961 * U+0E08 = CHO CHAN */
4962 /* <!ENTITY entity '&\u0e04\u0e08;'>\n */
4963 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 "
4964 "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n"
4965 /* ]>\n */
4966 "\0]\0>\0\n"
4967 /* <doc>&entity;</doc> */
4968 "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>";
4969
4970 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4971 != XML_STATUS_ERROR)
4972 fail("Invalid start of entity name not faulted");
4973 if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY)
4974 xml_failure(g_parser);
4975 }
4976 END_TEST
4977
START_TEST(test_invalid_character_entity_4)4978 START_TEST(test_invalid_character_entity_4) {
4979 const char *text = "<!DOCTYPE doc [\n"
4980 " <!ENTITY entity '�'>\n" /* = � */
4981 "]>\n"
4982 "<doc>&entity;</doc>";
4983
4984 expect_failure(text, XML_ERROR_BAD_CHAR_REF,
4985 "Out of range character reference not faulted");
4986 }
4987 END_TEST
4988
4989 /* Test that processing instructions are picked up by a default handler */
START_TEST(test_pi_handled_in_default)4990 START_TEST(test_pi_handled_in_default) {
4991 const char *text = "<?test processing instruction?>\n<doc/>";
4992 const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>");
4993 CharData storage;
4994
4995 CharData_Init(&storage);
4996 XML_SetDefaultHandler(g_parser, accumulate_characters);
4997 XML_SetUserData(g_parser, &storage);
4998 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4999 == XML_STATUS_ERROR)
5000 xml_failure(g_parser);
5001 CharData_CheckXMLChars(&storage, expected);
5002 }
5003 END_TEST
5004
5005 /* Test that comments are picked up by a default handler */
START_TEST(test_comment_handled_in_default)5006 START_TEST(test_comment_handled_in_default) {
5007 const char *text = "<!-- This is a comment -->\n<doc/>";
5008 const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>");
5009 CharData storage;
5010
5011 CharData_Init(&storage);
5012 XML_SetDefaultHandler(g_parser, accumulate_characters);
5013 XML_SetUserData(g_parser, &storage);
5014 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5015 == XML_STATUS_ERROR)
5016 xml_failure(g_parser);
5017 CharData_CheckXMLChars(&storage, expected);
5018 }
5019 END_TEST
5020
5021 /* Test PIs that look almost but not quite like XML declarations */
START_TEST(test_pi_yml)5022 START_TEST(test_pi_yml) {
5023 const char *text = "<?yml something like data?><doc/>";
5024 const XML_Char *expected = XCS("yml: something like data\n");
5025 CharData storage;
5026
5027 CharData_Init(&storage);
5028 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5029 XML_SetUserData(g_parser, &storage);
5030 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5031 == XML_STATUS_ERROR)
5032 xml_failure(g_parser);
5033 CharData_CheckXMLChars(&storage, expected);
5034 }
5035 END_TEST
5036
START_TEST(test_pi_xnl)5037 START_TEST(test_pi_xnl) {
5038 const char *text = "<?xnl nothing like data?><doc/>";
5039 const XML_Char *expected = XCS("xnl: nothing like data\n");
5040 CharData storage;
5041
5042 CharData_Init(&storage);
5043 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5044 XML_SetUserData(g_parser, &storage);
5045 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5046 == XML_STATUS_ERROR)
5047 xml_failure(g_parser);
5048 CharData_CheckXMLChars(&storage, expected);
5049 }
5050 END_TEST
5051
START_TEST(test_pi_xmm)5052 START_TEST(test_pi_xmm) {
5053 const char *text = "<?xmm everything like data?><doc/>";
5054 const XML_Char *expected = XCS("xmm: everything like data\n");
5055 CharData storage;
5056
5057 CharData_Init(&storage);
5058 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5059 XML_SetUserData(g_parser, &storage);
5060 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5061 == XML_STATUS_ERROR)
5062 xml_failure(g_parser);
5063 CharData_CheckXMLChars(&storage, expected);
5064 }
5065 END_TEST
5066
START_TEST(test_utf16_pi)5067 START_TEST(test_utf16_pi) {
5068 const char text[] =
5069 /* <?{KHO KHWAI}{CHO CHAN}?>
5070 * where {KHO KHWAI} = U+0E04
5071 * and {CHO CHAN} = U+0E08
5072 */
5073 "<\0?\0\x04\x0e\x08\x0e?\0>\0"
5074 /* <q/> */
5075 "<\0q\0/\0>\0";
5076 #ifdef XML_UNICODE
5077 const XML_Char *expected = XCS("\x0e04\x0e08: \n");
5078 #else
5079 const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
5080 #endif
5081 CharData storage;
5082
5083 CharData_Init(&storage);
5084 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5085 XML_SetUserData(g_parser, &storage);
5086 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5087 == XML_STATUS_ERROR)
5088 xml_failure(g_parser);
5089 CharData_CheckXMLChars(&storage, expected);
5090 }
5091 END_TEST
5092
START_TEST(test_utf16_be_pi)5093 START_TEST(test_utf16_be_pi) {
5094 const char text[] =
5095 /* <?{KHO KHWAI}{CHO CHAN}?>
5096 * where {KHO KHWAI} = U+0E04
5097 * and {CHO CHAN} = U+0E08
5098 */
5099 "\0<\0?\x0e\x04\x0e\x08\0?\0>"
5100 /* <q/> */
5101 "\0<\0q\0/\0>";
5102 #ifdef XML_UNICODE
5103 const XML_Char *expected = XCS("\x0e04\x0e08: \n");
5104 #else
5105 const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
5106 #endif
5107 CharData storage;
5108
5109 CharData_Init(&storage);
5110 XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5111 XML_SetUserData(g_parser, &storage);
5112 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5113 == XML_STATUS_ERROR)
5114 xml_failure(g_parser);
5115 CharData_CheckXMLChars(&storage, expected);
5116 }
5117 END_TEST
5118
5119 /* Test that comments can be picked up and translated */
START_TEST(test_utf16_be_comment)5120 START_TEST(test_utf16_be_comment) {
5121 const char text[] =
5122 /* <!-- Comment A --> */
5123 "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n"
5124 /* <doc/> */
5125 "\0<\0d\0o\0c\0/\0>";
5126 const XML_Char *expected = XCS(" Comment A ");
5127 CharData storage;
5128
5129 CharData_Init(&storage);
5130 XML_SetCommentHandler(g_parser, accumulate_comment);
5131 XML_SetUserData(g_parser, &storage);
5132 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5133 == XML_STATUS_ERROR)
5134 xml_failure(g_parser);
5135 CharData_CheckXMLChars(&storage, expected);
5136 }
5137 END_TEST
5138
START_TEST(test_utf16_le_comment)5139 START_TEST(test_utf16_le_comment) {
5140 const char text[] =
5141 /* <!-- Comment B --> */
5142 "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0"
5143 /* <doc/> */
5144 "<\0d\0o\0c\0/\0>\0";
5145 const XML_Char *expected = XCS(" Comment B ");
5146 CharData storage;
5147
5148 CharData_Init(&storage);
5149 XML_SetCommentHandler(g_parser, accumulate_comment);
5150 XML_SetUserData(g_parser, &storage);
5151 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5152 == XML_STATUS_ERROR)
5153 xml_failure(g_parser);
5154 CharData_CheckXMLChars(&storage, expected);
5155 }
5156 END_TEST
5157
5158 /* Test that the unknown encoding handler with map entries that expect
5159 * conversion but no conversion function is faulted
5160 */
START_TEST(test_missing_encoding_conversion_fn)5161 START_TEST(test_missing_encoding_conversion_fn) {
5162 const char *text = "<?xml version='1.0' encoding='no-conv'?>\n"
5163 "<doc>\x81</doc>";
5164
5165 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5166 /* MiscEncodingHandler sets up an encoding with every top-bit-set
5167 * character introducing a two-byte sequence. For this, it
5168 * requires a convert function. The above function call doesn't
5169 * pass one through, so when BadEncodingHandler actually gets
5170 * called it should supply an invalid encoding.
5171 */
5172 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5173 "Encoding with missing convert() not faulted");
5174 }
5175 END_TEST
5176
START_TEST(test_failing_encoding_conversion_fn)5177 START_TEST(test_failing_encoding_conversion_fn) {
5178 const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n"
5179 "<doc>\x81</doc>";
5180
5181 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5182 /* BadEncodingHandler sets up an encoding with every top-bit-set
5183 * character introducing a two-byte sequence. For this, it
5184 * requires a convert function. The above function call passes
5185 * one that insists all possible sequences are invalid anyway.
5186 */
5187 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5188 "Encoding with failing convert() not faulted");
5189 }
5190 END_TEST
5191
5192 /* Test unknown encoding conversions */
START_TEST(test_unknown_encoding_success)5193 START_TEST(test_unknown_encoding_success) {
5194 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5195 /* Equivalent to <eoc>Hello, world</eoc> */
5196 "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>";
5197
5198 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5199 run_character_check(text, XCS("Hello, world"));
5200 }
5201 END_TEST
5202
5203 /* Test bad name character in unknown encoding */
START_TEST(test_unknown_encoding_bad_name)5204 START_TEST(test_unknown_encoding_bad_name) {
5205 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5206 "<\xff\x64oc>Hello, world</\xff\x64oc>";
5207
5208 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5209 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5210 "Bad name start in unknown encoding not faulted");
5211 }
5212 END_TEST
5213
5214 /* Test bad mid-name character in unknown encoding */
START_TEST(test_unknown_encoding_bad_name_2)5215 START_TEST(test_unknown_encoding_bad_name_2) {
5216 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5217 "<d\xffoc>Hello, world</d\xffoc>";
5218
5219 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5220 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5221 "Bad name in unknown encoding not faulted");
5222 }
5223 END_TEST
5224
5225 /* Test element name that is long enough to fill the conversion buffer
5226 * in an unknown encoding, finishing with an encoded character.
5227 */
START_TEST(test_unknown_encoding_long_name_1)5228 START_TEST(test_unknown_encoding_long_name_1) {
5229 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5230 "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"
5231 "Hi"
5232 "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>";
5233 const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
5234 CharData storage;
5235
5236 CharData_Init(&storage);
5237 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5238 XML_SetStartElementHandler(g_parser, record_element_start_handler);
5239 XML_SetUserData(g_parser, &storage);
5240 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5241 == XML_STATUS_ERROR)
5242 xml_failure(g_parser);
5243 CharData_CheckXMLChars(&storage, expected);
5244 }
5245 END_TEST
5246
5247 /* Test element name that is long enough to fill the conversion buffer
5248 * in an unknown encoding, finishing with an simple character.
5249 */
START_TEST(test_unknown_encoding_long_name_2)5250 START_TEST(test_unknown_encoding_long_name_2) {
5251 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5252 "<abcdefghabcdefghabcdefghijklmnop>"
5253 "Hi"
5254 "</abcdefghabcdefghabcdefghijklmnop>";
5255 const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
5256 CharData storage;
5257
5258 CharData_Init(&storage);
5259 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5260 XML_SetStartElementHandler(g_parser, record_element_start_handler);
5261 XML_SetUserData(g_parser, &storage);
5262 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5263 == XML_STATUS_ERROR)
5264 xml_failure(g_parser);
5265 CharData_CheckXMLChars(&storage, expected);
5266 }
5267 END_TEST
5268
START_TEST(test_invalid_unknown_encoding)5269 START_TEST(test_invalid_unknown_encoding) {
5270 const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n"
5271 "<doc>Hello world</doc>";
5272
5273 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5274 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5275 "Invalid unknown encoding not faulted");
5276 }
5277 END_TEST
5278
START_TEST(test_unknown_ascii_encoding_ok)5279 START_TEST(test_unknown_ascii_encoding_ok) {
5280 const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
5281 "<doc>Hello, world</doc>";
5282
5283 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5284 run_character_check(text, XCS("Hello, world"));
5285 }
5286 END_TEST
5287
START_TEST(test_unknown_ascii_encoding_fail)5288 START_TEST(test_unknown_ascii_encoding_fail) {
5289 const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
5290 "<doc>Hello, \x80 world</doc>";
5291
5292 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5293 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5294 "Invalid character not faulted");
5295 }
5296 END_TEST
5297
START_TEST(test_unknown_encoding_invalid_length)5298 START_TEST(test_unknown_encoding_invalid_length) {
5299 const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n"
5300 "<doc>Hello, world</doc>";
5301
5302 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5303 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5304 "Invalid unknown encoding not faulted");
5305 }
5306 END_TEST
5307
START_TEST(test_unknown_encoding_invalid_topbit)5308 START_TEST(test_unknown_encoding_invalid_topbit) {
5309 const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n"
5310 "<doc>Hello, world</doc>";
5311
5312 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5313 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5314 "Invalid unknown encoding not faulted");
5315 }
5316 END_TEST
5317
START_TEST(test_unknown_encoding_invalid_surrogate)5318 START_TEST(test_unknown_encoding_invalid_surrogate) {
5319 const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n"
5320 "<doc>Hello, \x82 world</doc>";
5321
5322 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5323 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5324 "Invalid unknown encoding not faulted");
5325 }
5326 END_TEST
5327
START_TEST(test_unknown_encoding_invalid_high)5328 START_TEST(test_unknown_encoding_invalid_high) {
5329 const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n"
5330 "<doc>Hello, world</doc>";
5331
5332 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5333 expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5334 "Invalid unknown encoding not faulted");
5335 }
5336 END_TEST
5337
START_TEST(test_unknown_encoding_invalid_attr_value)5338 START_TEST(test_unknown_encoding_invalid_attr_value) {
5339 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5340 "<doc attr='\xff\x30'/>";
5341
5342 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5343 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5344 "Invalid attribute valid not faulted");
5345 }
5346 END_TEST
5347
START_TEST(test_unknown_encoding_user_data_primary)5348 START_TEST(test_unknown_encoding_user_data_primary) {
5349 // This test is based on ideas contributed by Artiphishell Inc.
5350 const char *const text = "<?xml version='1.0' encoding='x-unk'?>\n"
5351 "<root />\n";
5352 XML_Parser parser = XML_ParserCreate(NULL);
5353 XML_SetUnknownEncodingHandler(parser,
5354 user_data_checking_unknown_encoding_handler,
5355 (void *)(intptr_t)0xC0FFEE);
5356
5357 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
5358 == XML_STATUS_OK);
5359
5360 XML_ParserFree(parser);
5361 }
5362 END_TEST
5363
START_TEST(test_unknown_encoding_user_data_secondary)5364 START_TEST(test_unknown_encoding_user_data_secondary) {
5365 // This test is based on ideas contributed by Artiphishell Inc.
5366 const char *const text_main = "<!DOCTYPE r [\n"
5367 " <!ENTITY ext SYSTEM 'ext.ent'>\n"
5368 "]>\n"
5369 "<r>&ext;</r>\n";
5370 const char *const text_external = "<?xml version='1.0' encoding='x-unk'?>\n"
5371 "<e>data</e>";
5372 ExtTest2 test_data = {text_external, (int)strlen(text_external), NULL, NULL};
5373 XML_Parser parser = XML_ParserCreate(NULL);
5374 XML_SetExternalEntityRefHandler(parser, external_entity_loader2);
5375 XML_SetUnknownEncodingHandler(parser,
5376 user_data_checking_unknown_encoding_handler,
5377 (void *)(intptr_t)0xC0FFEE);
5378 XML_SetUserData(parser, &test_data);
5379
5380 assert_true(_XML_Parse_SINGLE_BYTES(parser, text_main, (int)strlen(text_main),
5381 XML_TRUE)
5382 == XML_STATUS_OK);
5383
5384 XML_ParserFree(parser);
5385 }
5386 END_TEST
5387
5388 /* Test an external entity parser set to use latin-1 detects UTF-16
5389 * BOMs correctly.
5390 */
5391 /* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */
START_TEST(test_ext_entity_latin1_utf16le_bom)5392 START_TEST(test_ext_entity_latin1_utf16le_bom) {
5393 const char *text = "<!DOCTYPE doc [\n"
5394 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5395 "]>\n"
5396 "<doc>&en;</doc>";
5397 ExtTest2 test_data
5398 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5399 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5400 * 0x4c = L and 0x20 is a space
5401 */
5402 "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL};
5403 #ifdef XML_UNICODE
5404 const XML_Char *expected = XCS("\x00ff\x00feL ");
5405 #else
5406 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5407 const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
5408 #endif
5409 CharData storage;
5410
5411 CharData_Init(&storage);
5412 test_data.storage = &storage;
5413 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5414 XML_SetUserData(g_parser, &test_data);
5415 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5416 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5417 == XML_STATUS_ERROR)
5418 xml_failure(g_parser);
5419 CharData_CheckXMLChars(&storage, expected);
5420 }
5421 END_TEST
5422
START_TEST(test_ext_entity_latin1_utf16be_bom)5423 START_TEST(test_ext_entity_latin1_utf16be_bom) {
5424 const char *text = "<!DOCTYPE doc [\n"
5425 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5426 "]>\n"
5427 "<doc>&en;</doc>";
5428 ExtTest2 test_data
5429 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5430 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5431 * 0x4c = L and 0x20 is a space
5432 */
5433 "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL};
5434 #ifdef XML_UNICODE
5435 const XML_Char *expected = XCS("\x00fe\x00ff L");
5436 #else
5437 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5438 const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L");
5439 #endif
5440 CharData storage;
5441
5442 CharData_Init(&storage);
5443 test_data.storage = &storage;
5444 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5445 XML_SetUserData(g_parser, &test_data);
5446 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5447 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5448 == XML_STATUS_ERROR)
5449 xml_failure(g_parser);
5450 CharData_CheckXMLChars(&storage, expected);
5451 }
5452 END_TEST
5453
5454 /* Parsing the full buffer rather than a byte at a time makes a
5455 * difference to the encoding scanning code, so repeat the above tests
5456 * without breaking them down by byte.
5457 */
START_TEST(test_ext_entity_latin1_utf16le_bom2)5458 START_TEST(test_ext_entity_latin1_utf16le_bom2) {
5459 const char *text = "<!DOCTYPE doc [\n"
5460 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5461 "]>\n"
5462 "<doc>&en;</doc>";
5463 ExtTest2 test_data
5464 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5465 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5466 * 0x4c = L and 0x20 is a space
5467 */
5468 "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL};
5469 #ifdef XML_UNICODE
5470 const XML_Char *expected = XCS("\x00ff\x00feL ");
5471 #else
5472 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5473 const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
5474 #endif
5475 CharData storage;
5476
5477 CharData_Init(&storage);
5478 test_data.storage = &storage;
5479 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5480 XML_SetUserData(g_parser, &test_data);
5481 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5482 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5483 == XML_STATUS_ERROR)
5484 xml_failure(g_parser);
5485 CharData_CheckXMLChars(&storage, expected);
5486 }
5487 END_TEST
5488
START_TEST(test_ext_entity_latin1_utf16be_bom2)5489 START_TEST(test_ext_entity_latin1_utf16be_bom2) {
5490 const char *text = "<!DOCTYPE doc [\n"
5491 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5492 "]>\n"
5493 "<doc>&en;</doc>";
5494 ExtTest2 test_data
5495 = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5496 /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5497 * 0x4c = L and 0x20 is a space
5498 */
5499 "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL};
5500 #ifdef XML_UNICODE
5501 const XML_Char *expected = XCS("\x00fe\x00ff L");
5502 #else
5503 /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5504 const XML_Char *expected = "\xc3\xbe\xc3\xbf L";
5505 #endif
5506 CharData storage;
5507
5508 CharData_Init(&storage);
5509 test_data.storage = &storage;
5510 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5511 XML_SetUserData(g_parser, &test_data);
5512 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5513 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5514 == XML_STATUS_ERROR)
5515 xml_failure(g_parser);
5516 CharData_CheckXMLChars(&storage, expected);
5517 }
5518 END_TEST
5519
5520 /* Test little-endian UTF-16 given an explicit big-endian encoding */
START_TEST(test_ext_entity_utf16_be)5521 START_TEST(test_ext_entity_utf16_be) {
5522 const char *text = "<!DOCTYPE doc [\n"
5523 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5524 "]>\n"
5525 "<doc>&en;</doc>";
5526 ExtTest2 test_data = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL};
5527 #ifdef XML_UNICODE
5528 const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
5529 #else
5530 const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
5531 "\xe6\x94\x80" /* U+6500 */
5532 "\xe2\xbc\x80" /* U+2F00 */
5533 "\xe3\xb8\x80"); /* U+3E00 */
5534 #endif
5535 CharData storage;
5536
5537 CharData_Init(&storage);
5538 test_data.storage = &storage;
5539 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5540 XML_SetUserData(g_parser, &test_data);
5541 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5542 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5543 == XML_STATUS_ERROR)
5544 xml_failure(g_parser);
5545 CharData_CheckXMLChars(&storage, expected);
5546 }
5547 END_TEST
5548
5549 /* Test big-endian UTF-16 given an explicit little-endian encoding */
START_TEST(test_ext_entity_utf16_le)5550 START_TEST(test_ext_entity_utf16_le) {
5551 const char *text = "<!DOCTYPE doc [\n"
5552 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5553 "]>\n"
5554 "<doc>&en;</doc>";
5555 ExtTest2 test_data = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL};
5556 #ifdef XML_UNICODE
5557 const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
5558 #else
5559 const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
5560 "\xe6\x94\x80" /* U+6500 */
5561 "\xe2\xbc\x80" /* U+2F00 */
5562 "\xe3\xb8\x80"); /* U+3E00 */
5563 #endif
5564 CharData storage;
5565
5566 CharData_Init(&storage);
5567 test_data.storage = &storage;
5568 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5569 XML_SetUserData(g_parser, &test_data);
5570 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5571 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5572 == XML_STATUS_ERROR)
5573 xml_failure(g_parser);
5574 CharData_CheckXMLChars(&storage, expected);
5575 }
5576 END_TEST
5577
5578 /* Test little-endian UTF-16 given no explicit encoding.
5579 * The existing default encoding (UTF-8) is assumed to hold without a
5580 * BOM to contradict it, so the entity value will in fact provoke an
5581 * error because 0x00 is not a valid XML character. We parse the
5582 * whole buffer in one go rather than feeding it in byte by byte to
5583 * exercise different code paths in the initial scanning routines.
5584 */
START_TEST(test_ext_entity_utf16_unknown)5585 START_TEST(test_ext_entity_utf16_unknown) {
5586 const char *text = "<!DOCTYPE doc [\n"
5587 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5588 "]>\n"
5589 "<doc>&en;</doc>";
5590 ExtFaults2 test_data
5591 = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL,
5592 XML_ERROR_INVALID_TOKEN};
5593
5594 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2);
5595 XML_SetUserData(g_parser, &test_data);
5596 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
5597 "Invalid character should not have been accepted");
5598 }
5599 END_TEST
5600
5601 /* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */
START_TEST(test_ext_entity_utf8_non_bom)5602 START_TEST(test_ext_entity_utf8_non_bom) {
5603 const char *text = "<!DOCTYPE doc [\n"
5604 " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5605 "]>\n"
5606 "<doc>&en;</doc>";
5607 ExtTest2 test_data
5608 = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */
5609 3, NULL, NULL};
5610 #ifdef XML_UNICODE
5611 const XML_Char *expected = XCS("\xfec0");
5612 #else
5613 const XML_Char *expected = XCS("\xef\xbb\x80");
5614 #endif
5615 CharData storage;
5616
5617 CharData_Init(&storage);
5618 test_data.storage = &storage;
5619 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5620 XML_SetUserData(g_parser, &test_data);
5621 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5622 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5623 == XML_STATUS_ERROR)
5624 xml_failure(g_parser);
5625 CharData_CheckXMLChars(&storage, expected);
5626 }
5627 END_TEST
5628
5629 /* Test that UTF-8 in a CDATA section is correctly passed through */
START_TEST(test_utf8_in_cdata_section)5630 START_TEST(test_utf8_in_cdata_section) {
5631 const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>";
5632 #ifdef XML_UNICODE
5633 const XML_Char *expected = XCS("one \x00e9 two");
5634 #else
5635 const XML_Char *expected = XCS("one \xc3\xa9 two");
5636 #endif
5637
5638 run_character_check(text, expected);
5639 }
5640 END_TEST
5641
5642 /* Test that little-endian UTF-16 in a CDATA section is handled */
START_TEST(test_utf8_in_cdata_section_2)5643 START_TEST(test_utf8_in_cdata_section_2) {
5644 const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>";
5645 #ifdef XML_UNICODE
5646 const XML_Char *expected = XCS("\x00e9]\x00e9two");
5647 #else
5648 const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two");
5649 #endif
5650
5651 run_character_check(text, expected);
5652 }
5653 END_TEST
5654
START_TEST(test_utf8_in_start_tags)5655 START_TEST(test_utf8_in_start_tags) {
5656 struct test_case {
5657 bool goodName;
5658 bool goodNameStart;
5659 const char *tagName;
5660 };
5661
5662 // The idea with the tests below is this:
5663 // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences
5664 // go to isNever and are hence not a concern.
5665 //
5666 // We start with a character that is a valid name character
5667 // (or even name-start character, see XML 1.0r4 spec) and then we flip
5668 // single bits at places where (1) the result leaves the UTF-8 encoding space
5669 // and (2) we stay in the same n-byte sequence family.
5670 //
5671 // The flipped bits are highlighted in angle brackets in comments,
5672 // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped
5673 // the most significant bit to 1 to leave UTF-8 encoding space.
5674 struct test_case cases[] = {
5675 // 1-byte UTF-8: [0xxx xxxx]
5676 {true, true, "\x3A"}, // [0011 1010] = ASCII colon ':'
5677 {false, false, "\xBA"}, // [<1>011 1010]
5678 {true, false, "\x39"}, // [0011 1001] = ASCII nine '9'
5679 {false, false, "\xB9"}, // [<1>011 1001]
5680
5681 // 2-byte UTF-8: [110x xxxx] [10xx xxxx]
5682 {true, true, "\xDB\xA5"}, // [1101 1011] [1010 0101] =
5683 // Arabic small waw U+06E5
5684 {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101]
5685 {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101]
5686 {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101]
5687 {true, false, "\xCC\x81"}, // [1100 1100] [1000 0001] =
5688 // combining char U+0301
5689 {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001]
5690 {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001]
5691 {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001]
5692
5693 // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx]
5694 {true, true, "\xE0\xA4\x85"}, // [1110 0000] [1010 0100] [1000 0101] =
5695 // Devanagari Letter A U+0905
5696 {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101]
5697 {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101]
5698 {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101]
5699 {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101]
5700 {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101]
5701 {true, false, "\xE0\xA4\x81"}, // [1110 0000] [1010 0100] [1000 0001] =
5702 // combining char U+0901
5703 {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001]
5704 {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001]
5705 {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001]
5706 {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001]
5707 {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001]
5708 };
5709 const bool atNameStart[] = {true, false};
5710
5711 size_t i = 0;
5712 char doc[1024];
5713 size_t failCount = 0;
5714
5715 // we need all the bytes to be parsed, but we don't want the errors that can
5716 // trigger on isFinal=XML_TRUE, so we skip the test if the heuristic is on.
5717 if (g_reparseDeferralEnabledDefault) {
5718 return;
5719 }
5720
5721 for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
5722 size_t j = 0;
5723 for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) {
5724 const bool expectedSuccess
5725 = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName;
5726 snprintf(doc, sizeof(doc), "<%s%s><!--", atNameStart[j] ? "" : "a",
5727 cases[i].tagName);
5728 XML_Parser parser = XML_ParserCreate(NULL);
5729
5730 const enum XML_Status status = _XML_Parse_SINGLE_BYTES(
5731 parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE);
5732
5733 bool success = true;
5734 if ((status == XML_STATUS_OK) != expectedSuccess) {
5735 success = false;
5736 }
5737 if ((status == XML_STATUS_ERROR)
5738 && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) {
5739 success = false;
5740 }
5741
5742 if (! success) {
5743 fprintf(
5744 stderr,
5745 "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n",
5746 (unsigned)i + 1u, atNameStart[j] ? " " : "not ",
5747 (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser));
5748 failCount++;
5749 }
5750
5751 XML_ParserFree(parser);
5752 }
5753 }
5754
5755 if (failCount > 0) {
5756 fail("UTF-8 regression detected");
5757 }
5758 }
5759 END_TEST
5760
5761 /* Test trailing spaces in elements are accepted */
START_TEST(test_trailing_spaces_in_elements)5762 START_TEST(test_trailing_spaces_in_elements) {
5763 const char *text = "<doc >Hi</doc >";
5764 const XML_Char *expected = XCS("doc/doc");
5765 CharData storage;
5766
5767 CharData_Init(&storage);
5768 XML_SetElementHandler(g_parser, record_element_start_handler,
5769 record_element_end_handler);
5770 XML_SetUserData(g_parser, &storage);
5771 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5772 == XML_STATUS_ERROR)
5773 xml_failure(g_parser);
5774 CharData_CheckXMLChars(&storage, expected);
5775 }
5776 END_TEST
5777
START_TEST(test_utf16_attribute)5778 START_TEST(test_utf16_attribute) {
5779 const char text[] =
5780 /* <d {KHO KHWAI}{CHO CHAN}='a'/>
5781 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
5782 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
5783 */
5784 "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0";
5785 const XML_Char *expected = XCS("a");
5786 CharData storage;
5787
5788 CharData_Init(&storage);
5789 XML_SetStartElementHandler(g_parser, accumulate_attribute);
5790 XML_SetUserData(g_parser, &storage);
5791 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5792 == XML_STATUS_ERROR)
5793 xml_failure(g_parser);
5794 CharData_CheckXMLChars(&storage, expected);
5795 }
5796 END_TEST
5797
START_TEST(test_utf16_second_attr)5798 START_TEST(test_utf16_second_attr) {
5799 /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/>
5800 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
5801 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
5802 */
5803 const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0"
5804 "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0";
5805 const XML_Char *expected = XCS("1");
5806 CharData storage;
5807
5808 CharData_Init(&storage);
5809 XML_SetStartElementHandler(g_parser, accumulate_attribute);
5810 XML_SetUserData(g_parser, &storage);
5811 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5812 == XML_STATUS_ERROR)
5813 xml_failure(g_parser);
5814 CharData_CheckXMLChars(&storage, expected);
5815 }
5816 END_TEST
5817
START_TEST(test_attr_after_solidus)5818 START_TEST(test_attr_after_solidus) {
5819 const char *text = "<doc attr1='a' / attr2='b'>";
5820
5821 expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted");
5822 }
5823 END_TEST
5824
START_TEST(test_utf16_pe)5825 START_TEST(test_utf16_pe) {
5826 /* <!DOCTYPE doc [
5827 * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'>
5828 * %{KHO KHWAI}{CHO CHAN};
5829 * ]>
5830 * <doc></doc>
5831 *
5832 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
5833 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
5834 */
5835 const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
5836 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 "
5837 "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 "
5838 "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n"
5839 "\0%\x0e\x04\x0e\x08\0;\0\n"
5840 "\0]\0>\0\n"
5841 "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>";
5842 #ifdef XML_UNICODE
5843 const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n");
5844 #else
5845 const XML_Char *expected
5846 = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n");
5847 #endif
5848 CharData storage;
5849
5850 CharData_Init(&storage);
5851 XML_SetUserData(g_parser, &storage);
5852 XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl);
5853 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5854 == XML_STATUS_ERROR)
5855 xml_failure(g_parser);
5856 CharData_CheckXMLChars(&storage, expected);
5857 }
5858 END_TEST
5859
5860 /* Test that duff attribute description keywords are rejected */
START_TEST(test_bad_attr_desc_keyword)5861 START_TEST(test_bad_attr_desc_keyword) {
5862 const char *text = "<!DOCTYPE doc [\n"
5863 " <!ATTLIST doc attr CDATA #!IMPLIED>\n"
5864 "]>\n"
5865 "<doc />";
5866
5867 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5868 "Bad keyword !IMPLIED not faulted");
5869 }
5870 END_TEST
5871
5872 /* Test that an invalid attribute description keyword consisting of
5873 * UTF-16 characters with their top bytes non-zero are correctly
5874 * faulted
5875 */
START_TEST(test_bad_attr_desc_keyword_utf16)5876 START_TEST(test_bad_attr_desc_keyword_utf16) {
5877 /* <!DOCTYPE d [
5878 * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}>
5879 * ]><d/>
5880 *
5881 * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
5882 * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
5883 */
5884 const char text[]
5885 = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
5886 "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 "
5887 "\0#\x0e\x04\x0e\x08\0>\0\n"
5888 "\0]\0>\0<\0d\0/\0>";
5889
5890 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5891 != XML_STATUS_ERROR)
5892 fail("Invalid UTF16 attribute keyword not faulted");
5893 if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
5894 xml_failure(g_parser);
5895 }
5896 END_TEST
5897
5898 /* Test that invalid syntax in a <!DOCTYPE> is rejected. Do this
5899 * using prefix-encoding (see above) to trigger specific code paths
5900 */
START_TEST(test_bad_doctype)5901 START_TEST(test_bad_doctype) {
5902 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5903 "<!DOCTYPE doc [ \x80\x44 ]><doc/>";
5904
5905 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5906 expect_failure(text, XML_ERROR_SYNTAX,
5907 "Invalid bytes in DOCTYPE not faulted");
5908 }
5909 END_TEST
5910
START_TEST(test_bad_doctype_utf8)5911 START_TEST(test_bad_doctype_utf8) {
5912 const char *text = "<!DOCTYPE \xDB\x25"
5913 "doc><doc/>"; // [1101 1011] [<0>010 0101]
5914 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5915 "Invalid UTF-8 in DOCTYPE not faulted");
5916 }
5917 END_TEST
5918
START_TEST(test_bad_doctype_utf16)5919 START_TEST(test_bad_doctype_utf16) {
5920 const char text[] =
5921 /* <!DOCTYPE doc [ \x06f2 ]><doc/>
5922 *
5923 * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number
5924 * (name character) but not a valid letter (name start character)
5925 */
5926 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 "
5927 "\x06\xf2"
5928 "\0 \0]\0>\0<\0d\0o\0c\0/\0>";
5929
5930 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5931 != XML_STATUS_ERROR)
5932 fail("Invalid bytes in DOCTYPE not faulted");
5933 if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
5934 xml_failure(g_parser);
5935 }
5936 END_TEST
5937
START_TEST(test_bad_doctype_plus)5938 START_TEST(test_bad_doctype_plus) {
5939 const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n"
5940 "<1+>&foo;</1+>";
5941
5942 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5943 "'+' in document name not faulted");
5944 }
5945 END_TEST
5946
START_TEST(test_bad_doctype_star)5947 START_TEST(test_bad_doctype_star) {
5948 const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n"
5949 "<1*>&foo;</1*>";
5950
5951 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5952 "'*' in document name not faulted");
5953 }
5954 END_TEST
5955
START_TEST(test_bad_doctype_query)5956 START_TEST(test_bad_doctype_query) {
5957 const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n"
5958 "<1?>&foo;</1?>";
5959
5960 expect_failure(text, XML_ERROR_INVALID_TOKEN,
5961 "'?' in document name not faulted");
5962 }
5963 END_TEST
5964
START_TEST(test_unknown_encoding_bad_ignore)5965 START_TEST(test_unknown_encoding_bad_ignore) {
5966 const char *text = "<?xml version='1.0' encoding='prefix-conv'?>"
5967 "<!DOCTYPE doc SYSTEM 'foo'>"
5968 "<doc><e>&entity;</e></doc>";
5969 ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>",
5970 "Invalid character not faulted", XCS("prefix-conv"),
5971 XML_ERROR_INVALID_TOKEN};
5972
5973 XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5974 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5975 XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
5976 XML_SetUserData(g_parser, &fault);
5977 expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
5978 "Bad IGNORE section with unknown encoding not failed");
5979 }
5980 END_TEST
5981
START_TEST(test_entity_in_utf16_be_attr)5982 START_TEST(test_entity_in_utf16_be_attr) {
5983 const char text[] =
5984 /* <e a='ä ä'></e> */
5985 "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 "
5986 "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>";
5987 #ifdef XML_UNICODE
5988 const XML_Char *expected = XCS("\x00e4 \x00e4");
5989 #else
5990 const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
5991 #endif
5992 CharData storage;
5993
5994 CharData_Init(&storage);
5995 XML_SetUserData(g_parser, &storage);
5996 XML_SetStartElementHandler(g_parser, accumulate_attribute);
5997 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5998 == XML_STATUS_ERROR)
5999 xml_failure(g_parser);
6000 CharData_CheckXMLChars(&storage, expected);
6001 }
6002 END_TEST
6003
START_TEST(test_entity_in_utf16_le_attr)6004 START_TEST(test_entity_in_utf16_le_attr) {
6005 const char text[] =
6006 /* <e a='ä ä'></e> */
6007 "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0"
6008 "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0";
6009 #ifdef XML_UNICODE
6010 const XML_Char *expected = XCS("\x00e4 \x00e4");
6011 #else
6012 const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
6013 #endif
6014 CharData storage;
6015
6016 CharData_Init(&storage);
6017 XML_SetUserData(g_parser, &storage);
6018 XML_SetStartElementHandler(g_parser, accumulate_attribute);
6019 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6020 == XML_STATUS_ERROR)
6021 xml_failure(g_parser);
6022 CharData_CheckXMLChars(&storage, expected);
6023 }
6024 END_TEST
6025
START_TEST(test_entity_public_utf16_be)6026 START_TEST(test_entity_public_utf16_be) {
6027 const char text[] =
6028 /* <!DOCTYPE d [ */
6029 "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
6030 /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
6031 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 "
6032 "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n"
6033 /* %e; */
6034 "\0%\0e\0;\0\n"
6035 /* ]> */
6036 "\0]\0>\0\n"
6037 /* <d>&j;</d> */
6038 "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>";
6039 ExtTest2 test_data
6040 = {/* <!ENTITY j 'baz'> */
6041 "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>", 34, NULL, NULL};
6042 const XML_Char *expected = XCS("baz");
6043 CharData storage;
6044
6045 CharData_Init(&storage);
6046 test_data.storage = &storage;
6047 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6048 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
6049 XML_SetUserData(g_parser, &test_data);
6050 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
6051 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6052 == XML_STATUS_ERROR)
6053 xml_failure(g_parser);
6054 CharData_CheckXMLChars(&storage, expected);
6055 }
6056 END_TEST
6057
START_TEST(test_entity_public_utf16_le)6058 START_TEST(test_entity_public_utf16_le) {
6059 const char text[] =
6060 /* <!DOCTYPE d [ */
6061 "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
6062 /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
6063 "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0"
6064 "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0"
6065 /* %e; */
6066 "%\0e\0;\0\n\0"
6067 /* ]> */
6068 "]\0>\0\n\0"
6069 /* <d>&j;</d> */
6070 "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0";
6071 ExtTest2 test_data
6072 = {/* <!ENTITY j 'baz'> */
6073 "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0", 34, NULL, NULL};
6074 const XML_Char *expected = XCS("baz");
6075 CharData storage;
6076
6077 CharData_Init(&storage);
6078 test_data.storage = &storage;
6079 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6080 XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
6081 XML_SetUserData(g_parser, &test_data);
6082 XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
6083 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6084 == XML_STATUS_ERROR)
6085 xml_failure(g_parser);
6086 CharData_CheckXMLChars(&storage, expected);
6087 }
6088 END_TEST
6089
6090 /* Test that a doctype with neither an internal nor external subset is
6091 * faulted
6092 */
START_TEST(test_short_doctype)6093 START_TEST(test_short_doctype) {
6094 const char *text = "<!DOCTYPE doc></doc>";
6095 expect_failure(text, XML_ERROR_INVALID_TOKEN,
6096 "DOCTYPE without subset not rejected");
6097 }
6098 END_TEST
6099
START_TEST(test_short_doctype_2)6100 START_TEST(test_short_doctype_2) {
6101 const char *text = "<!DOCTYPE doc PUBLIC></doc>";
6102 expect_failure(text, XML_ERROR_SYNTAX,
6103 "DOCTYPE without Public ID not rejected");
6104 }
6105 END_TEST
6106
START_TEST(test_short_doctype_3)6107 START_TEST(test_short_doctype_3) {
6108 const char *text = "<!DOCTYPE doc SYSTEM></doc>";
6109 expect_failure(text, XML_ERROR_SYNTAX,
6110 "DOCTYPE without System ID not rejected");
6111 }
6112 END_TEST
6113
START_TEST(test_long_doctype)6114 START_TEST(test_long_doctype) {
6115 const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>";
6116 expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected");
6117 }
6118 END_TEST
6119
START_TEST(test_bad_entity)6120 START_TEST(test_bad_entity) {
6121 const char *text = "<!DOCTYPE doc [\n"
6122 " <!ENTITY foo PUBLIC>\n"
6123 "]>\n"
6124 "<doc/>";
6125 expect_failure(text, XML_ERROR_SYNTAX,
6126 "ENTITY without Public ID is not rejected");
6127 }
6128 END_TEST
6129
6130 /* Test unquoted value is faulted */
START_TEST(test_bad_entity_2)6131 START_TEST(test_bad_entity_2) {
6132 const char *text = "<!DOCTYPE doc [\n"
6133 " <!ENTITY % foo bar>\n"
6134 "]>\n"
6135 "<doc/>";
6136 expect_failure(text, XML_ERROR_SYNTAX,
6137 "ENTITY without Public ID is not rejected");
6138 }
6139 END_TEST
6140
START_TEST(test_bad_entity_3)6141 START_TEST(test_bad_entity_3) {
6142 const char *text = "<!DOCTYPE doc [\n"
6143 " <!ENTITY % foo PUBLIC>\n"
6144 "]>\n"
6145 "<doc/>";
6146 expect_failure(text, XML_ERROR_SYNTAX,
6147 "Parameter ENTITY without Public ID is not rejected");
6148 }
6149 END_TEST
6150
START_TEST(test_bad_entity_4)6151 START_TEST(test_bad_entity_4) {
6152 const char *text = "<!DOCTYPE doc [\n"
6153 " <!ENTITY % foo SYSTEM>\n"
6154 "]>\n"
6155 "<doc/>";
6156 expect_failure(text, XML_ERROR_SYNTAX,
6157 "Parameter ENTITY without Public ID is not rejected");
6158 }
6159 END_TEST
6160
START_TEST(test_bad_notation)6161 START_TEST(test_bad_notation) {
6162 const char *text = "<!DOCTYPE doc [\n"
6163 " <!NOTATION n SYSTEM>\n"
6164 "]>\n"
6165 "<doc/>";
6166 expect_failure(text, XML_ERROR_SYNTAX,
6167 "Notation without System ID is not rejected");
6168 }
6169 END_TEST
6170
6171 /* Test for issue #11, wrongly suppressed default handler */
START_TEST(test_default_doctype_handler)6172 START_TEST(test_default_doctype_handler) {
6173 const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n"
6174 " <!ENTITY foo 'bar'>\n"
6175 "]>\n"
6176 "<doc>&foo;</doc>";
6177 DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE},
6178 {XCS("'test.dtd'"), 10, XML_FALSE},
6179 {NULL, 0, XML_FALSE}};
6180 int i;
6181
6182 XML_SetUserData(g_parser, &test_data);
6183 XML_SetDefaultHandler(g_parser, checking_default_handler);
6184 XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
6185 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6186 == XML_STATUS_ERROR)
6187 xml_failure(g_parser);
6188 for (i = 0; test_data[i].expected != NULL; i++)
6189 if (! test_data[i].seen)
6190 fail("Default handler not run for public !DOCTYPE");
6191 }
6192 END_TEST
6193
START_TEST(test_empty_element_abort)6194 START_TEST(test_empty_element_abort) {
6195 const char *text = "<abort/>";
6196
6197 XML_SetStartElementHandler(g_parser, start_element_suspender);
6198 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6199 != XML_STATUS_ERROR)
6200 fail("Expected to error on abort");
6201 }
6202 END_TEST
6203
6204 /* Regression test for GH issue #612: unfinished m_declAttributeType
6205 * allocation in ->m_tempPool can corrupt following allocation.
6206 */
START_TEST(test_pool_integrity_with_unfinished_attr)6207 START_TEST(test_pool_integrity_with_unfinished_attr) {
6208 const char *text = "<?xml version='1.0' encoding='UTF-8'?>\n"
6209 "<!DOCTYPE foo [\n"
6210 "<!ELEMENT foo ANY>\n"
6211 "<!ENTITY % entp SYSTEM \"external.dtd\">\n"
6212 "%entp;\n"
6213 "]>\n"
6214 "<a></a>\n";
6215 const XML_Char *expected = XCS("COMMENT");
6216 CharData storage;
6217
6218 CharData_Init(&storage);
6219 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6220 XML_SetExternalEntityRefHandler(g_parser, external_entity_unfinished_attlist);
6221 XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
6222 XML_SetCommentHandler(g_parser, accumulate_comment);
6223 XML_SetUserData(g_parser, &storage);
6224 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6225 == XML_STATUS_ERROR)
6226 xml_failure(g_parser);
6227 CharData_CheckXMLChars(&storage, expected);
6228 }
6229 END_TEST
6230
6231 /* Test a possible early return location in internalEntityProcessor */
START_TEST(test_entity_ref_no_elements)6232 START_TEST(test_entity_ref_no_elements) {
6233 const char *const text = "<!DOCTYPE foo [\n"
6234 "<!ENTITY e1 \"test\">\n"
6235 "]> <foo>&e1;"; // intentionally missing newline
6236
6237 XML_Parser parser = XML_ParserCreate(NULL);
6238 assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
6239 == XML_STATUS_ERROR);
6240 assert_true(XML_GetErrorCode(parser) == XML_ERROR_NO_ELEMENTS);
6241 XML_ParserFree(parser);
6242 }
6243 END_TEST
6244
6245 /* Tests if chained entity references lead to unbounded recursion */
START_TEST(test_deep_nested_entity)6246 START_TEST(test_deep_nested_entity) {
6247 const size_t N_LINES = 60000;
6248 const size_t SIZE_PER_LINE = 50;
6249
6250 char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE);
6251 if (text == NULL) {
6252 fail("malloc failed");
6253 }
6254
6255 char *textPtr = text;
6256
6257 // Create the XML
6258 textPtr += snprintf(textPtr, SIZE_PER_LINE,
6259 "<!DOCTYPE foo [\n"
6260 " <!ENTITY s0 'deepText'>\n");
6261
6262 for (size_t i = 1; i < N_LINES; ++i) {
6263 textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n",
6264 (long unsigned)i, (long unsigned)(i - 1));
6265 }
6266
6267 snprintf(textPtr, SIZE_PER_LINE, "]> <foo>&s%lu;</foo>\n",
6268 (long unsigned)(N_LINES - 1));
6269
6270 const XML_Char *const expected = XCS("deepText");
6271
6272 CharData storage;
6273 CharData_Init(&storage);
6274
6275 XML_Parser parser = XML_ParserCreate(NULL);
6276
6277 XML_SetCharacterDataHandler(parser, accumulate_characters);
6278 XML_SetUserData(parser, &storage);
6279
6280 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
6281 == XML_STATUS_ERROR)
6282 xml_failure(parser);
6283
6284 CharData_CheckXMLChars(&storage, expected);
6285 XML_ParserFree(parser);
6286 free(text);
6287 }
6288 END_TEST
6289
6290 /* Tests if chained entity references in attributes
6291 lead to unbounded recursion */
START_TEST(test_deep_nested_attribute_entity)6292 START_TEST(test_deep_nested_attribute_entity) {
6293 const size_t N_LINES = 60000;
6294 const size_t SIZE_PER_LINE = 100;
6295
6296 char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE);
6297 if (text == NULL) {
6298 fail("malloc failed");
6299 }
6300
6301 char *textPtr = text;
6302
6303 // Create the XML
6304 textPtr += snprintf(textPtr, SIZE_PER_LINE,
6305 "<!DOCTYPE foo [\n"
6306 " <!ENTITY s0 'deepText'>\n");
6307
6308 for (size_t i = 1; i < N_LINES; ++i) {
6309 textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n",
6310 (long unsigned)i, (long unsigned)(i - 1));
6311 }
6312
6313 snprintf(textPtr, SIZE_PER_LINE, "]> <foo name='&s%lu;'>mainText</foo>\n",
6314 (long unsigned)(N_LINES - 1));
6315
6316 AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}};
6317 ElementInfo info[]
6318 = {{XCS("foo"), 1, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
6319
6320 XML_Parser parser = XML_ParserCreate(NULL);
6321 ParserAndElementInfo parserPlusElemenInfo = {parser, info};
6322
6323 XML_SetStartElementHandler(parser, counting_start_element_handler);
6324 XML_SetUserData(parser, &parserPlusElemenInfo);
6325
6326 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
6327 == XML_STATUS_ERROR)
6328 xml_failure(parser);
6329
6330 XML_ParserFree(parser);
6331 free(text);
6332 }
6333 END_TEST
6334
START_TEST(test_deep_nested_entity_delayed_interpretation)6335 START_TEST(test_deep_nested_entity_delayed_interpretation) {
6336 const size_t N_LINES = 70000;
6337 const size_t SIZE_PER_LINE = 100;
6338
6339 char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE);
6340 if (text == NULL) {
6341 fail("malloc failed");
6342 }
6343
6344 char *textPtr = text;
6345
6346 // Create the XML
6347 textPtr += snprintf(textPtr, SIZE_PER_LINE,
6348 "<!DOCTYPE foo [\n"
6349 " <!ENTITY %% s0 'deepText'>\n");
6350
6351 for (size_t i = 1; i < N_LINES; ++i) {
6352 textPtr += snprintf(textPtr, SIZE_PER_LINE,
6353 " <!ENTITY %% s%lu '%s%lu;'>\n", (long unsigned)i,
6354 (long unsigned)(i - 1));
6355 }
6356
6357 snprintf(textPtr, SIZE_PER_LINE,
6358 " <!ENTITY %% define_g \"<!ENTITY g '%s%lu;'>\">\n"
6359 " %%define_g;\n"
6360 "]>\n"
6361 "<foo/>\n",
6362 (long unsigned)(N_LINES - 1));
6363
6364 XML_Parser parser = XML_ParserCreate(NULL);
6365
6366 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6367 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
6368 == XML_STATUS_ERROR)
6369 xml_failure(parser);
6370
6371 XML_ParserFree(parser);
6372 free(text);
6373 }
6374 END_TEST
6375
START_TEST(test_nested_entity_suspend)6376 START_TEST(test_nested_entity_suspend) {
6377 const char *const text = "<!DOCTYPE a [\n"
6378 " <!ENTITY e1 '<!--e1-->'>\n"
6379 " <!ENTITY e2 '<!--e2 head-->&e1;<!--e2 tail-->'>\n"
6380 " <!ENTITY e3 '<!--e3 head-->&e2;<!--e3 tail-->'>\n"
6381 "]>\n"
6382 "<a><!--start-->&e3;<!--end--></a>";
6383 const XML_Char *const expected = XCS("start") XCS("e3 head") XCS("e2 head")
6384 XCS("e1") XCS("e2 tail") XCS("e3 tail") XCS("end");
6385 CharData storage;
6386 CharData_Init(&storage);
6387 XML_Parser parser = XML_ParserCreate(NULL);
6388 ParserPlusStorage parserPlusStorage = {parser, &storage};
6389
6390 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6391 XML_SetCommentHandler(parser, accumulate_and_suspend_comment_handler);
6392 XML_SetUserData(parser, &parserPlusStorage);
6393
6394 enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE);
6395 while (status == XML_STATUS_SUSPENDED) {
6396 status = XML_ResumeParser(parser);
6397 }
6398 if (status != XML_STATUS_OK)
6399 xml_failure(parser);
6400
6401 CharData_CheckXMLChars(&storage, expected);
6402 XML_ParserFree(parser);
6403 }
6404 END_TEST
6405
START_TEST(test_nested_entity_suspend_2)6406 START_TEST(test_nested_entity_suspend_2) {
6407 const char *const text = "<!DOCTYPE doc [\n"
6408 " <!ENTITY ge1 'head1Ztail1'>\n"
6409 " <!ENTITY ge2 'head2&ge1;tail2'>\n"
6410 " <!ENTITY ge3 'head3&ge2;tail3'>\n"
6411 "]>\n"
6412 "<doc>&ge3;</doc>";
6413 const XML_Char *const expected = XCS("head3") XCS("head2") XCS("head1")
6414 XCS("Z") XCS("tail1") XCS("tail2") XCS("tail3");
6415 CharData storage;
6416 CharData_Init(&storage);
6417 XML_Parser parser = XML_ParserCreate(NULL);
6418 ParserPlusStorage parserPlusStorage = {parser, &storage};
6419
6420 XML_SetCharacterDataHandler(parser, accumulate_char_data_and_suspend);
6421 XML_SetUserData(parser, &parserPlusStorage);
6422
6423 enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE);
6424 while (status == XML_STATUS_SUSPENDED) {
6425 status = XML_ResumeParser(parser);
6426 }
6427 if (status != XML_STATUS_OK)
6428 xml_failure(parser);
6429
6430 CharData_CheckXMLChars(&storage, expected);
6431 XML_ParserFree(parser);
6432 }
6433 END_TEST
6434
6435 /* Regression test for quadratic parsing on large tokens */
START_TEST(test_big_tokens_scale_linearly)6436 START_TEST(test_big_tokens_scale_linearly) {
6437 const struct {
6438 const char *pre;
6439 const char *post;
6440 } text[] = {
6441 {"<a>", "</a>"}, // assumed good, used as baseline
6442 {"<b><![CDATA[ value: ", " ]]></b>"}, // CDATA, performed OK before patch
6443 {"<c attr='", "'></c>"}, // big attribute, used to be O(N²)
6444 {"<d><!-- ", " --></d>"}, // long comment, used to be O(N²)
6445 {"<e><", "/></e>"}, // big elem name, used to be O(N²)
6446 };
6447 const int num_cases = sizeof(text) / sizeof(text[0]);
6448 char aaaaaa[4096];
6449 const int fillsize = (int)sizeof(aaaaaa);
6450 const int fillcount = 100;
6451 const unsigned approx_bytes = fillsize * fillcount; // ignore pre/post.
6452 const unsigned max_factor = 4;
6453 const unsigned max_scanned = max_factor * approx_bytes;
6454
6455 memset(aaaaaa, 'a', fillsize);
6456
6457 if (! g_reparseDeferralEnabledDefault) {
6458 return; // heuristic is disabled; we would get O(n^2) and fail.
6459 }
6460
6461 for (int i = 0; i < num_cases; ++i) {
6462 XML_Parser parser = XML_ParserCreate(NULL);
6463 assert_true(parser != NULL);
6464 enum XML_Status status;
6465 set_subtest("text=\"%saaaaaa%s\"", text[i].pre, text[i].post);
6466
6467 // parse the start text
6468 g_bytesScanned = 0;
6469 status = _XML_Parse_SINGLE_BYTES(parser, text[i].pre,
6470 (int)strlen(text[i].pre), XML_FALSE);
6471 if (status != XML_STATUS_OK) {
6472 xml_failure(parser);
6473 }
6474
6475 // parse lots of 'a', failing the test early if it takes too long
6476 unsigned past_max_count = 0;
6477 for (int f = 0; f < fillcount; ++f) {
6478 status = _XML_Parse_SINGLE_BYTES(parser, aaaaaa, fillsize, XML_FALSE);
6479 if (status != XML_STATUS_OK) {
6480 xml_failure(parser);
6481 }
6482 if (g_bytesScanned > max_scanned) {
6483 // We're not done, and have already passed the limit -- the test will
6484 // definitely fail. This block allows us to save time by failing early.
6485 const unsigned pushed
6486 = (unsigned)strlen(text[i].pre) + (f + 1) * fillsize;
6487 fprintf(
6488 stderr,
6489 "after %d/%d loops: pushed=%u scanned=%u (factor ~%.2f) max_scanned: %u (factor ~%u)\n",
6490 f + 1, fillcount, pushed, g_bytesScanned,
6491 g_bytesScanned / (double)pushed, max_scanned, max_factor);
6492 past_max_count++;
6493 // We are failing, but allow a few log prints first. If we don't reach
6494 // a count of five, the test will fail after the loop instead.
6495 assert_true(past_max_count < 5);
6496 }
6497 }
6498
6499 // parse the end text
6500 status = _XML_Parse_SINGLE_BYTES(parser, text[i].post,
6501 (int)strlen(text[i].post), XML_TRUE);
6502 if (status != XML_STATUS_OK) {
6503 xml_failure(parser);
6504 }
6505
6506 assert_true(g_bytesScanned > approx_bytes); // or the counter isn't working
6507 if (g_bytesScanned > max_scanned) {
6508 fprintf(
6509 stderr,
6510 "after all input: scanned=%u (factor ~%.2f) max_scanned: %u (factor ~%u)\n",
6511 g_bytesScanned, g_bytesScanned / (double)approx_bytes, max_scanned,
6512 max_factor);
6513 fail("scanned too many bytes");
6514 }
6515
6516 XML_ParserFree(parser);
6517 }
6518 }
6519 END_TEST
6520
START_TEST(test_set_reparse_deferral)6521 START_TEST(test_set_reparse_deferral) {
6522 const char *const pre = "<d>";
6523 const char *const start = "<x attr='";
6524 const char *const end = "'></x>";
6525 char eeeeee[100];
6526 const int fillsize = (int)sizeof(eeeeee);
6527 memset(eeeeee, 'e', fillsize);
6528
6529 for (int enabled = 0; enabled <= 1; enabled += 1) {
6530 set_subtest("deferral=%d", enabled);
6531
6532 XML_Parser parser = XML_ParserCreate(NULL);
6533 assert_true(parser != NULL);
6534 assert_true(XML_SetReparseDeferralEnabled(parser, enabled));
6535 // pre-grow the buffer to avoid reparsing due to almost-fullness
6536 assert_true(XML_GetBuffer(parser, fillsize * 10103) != NULL);
6537
6538 CharData storage;
6539 CharData_Init(&storage);
6540 XML_SetUserData(parser, &storage);
6541 XML_SetStartElementHandler(parser, start_element_event_handler);
6542
6543 enum XML_Status status;
6544 // parse the start text
6545 status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE);
6546 if (status != XML_STATUS_OK) {
6547 xml_failure(parser);
6548 }
6549 CharData_CheckXMLChars(&storage, XCS("d")); // first element should be done
6550
6551 // ..and the start of the token
6552 status = XML_Parse(parser, start, (int)strlen(start), XML_FALSE);
6553 if (status != XML_STATUS_OK) {
6554 xml_failure(parser);
6555 }
6556 CharData_CheckXMLChars(&storage, XCS("d")); // still just the first one
6557
6558 // try to parse lots of 'e', but the token isn't finished
6559 for (int c = 0; c < 100; ++c) {
6560 status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE);
6561 if (status != XML_STATUS_OK) {
6562 xml_failure(parser);
6563 }
6564 }
6565 CharData_CheckXMLChars(&storage, XCS("d")); // *still* just the first one
6566
6567 // end the <x> token.
6568 status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE);
6569 if (status != XML_STATUS_OK) {
6570 xml_failure(parser);
6571 }
6572
6573 if (enabled) {
6574 // In general, we may need to push more data to trigger a reparse attempt,
6575 // but in this test, the data is constructed to always require it.
6576 CharData_CheckXMLChars(&storage, XCS("d")); // or the test is incorrect
6577 // 2x the token length should suffice; the +1 covers the start and end.
6578 for (int c = 0; c < 101; ++c) {
6579 status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE);
6580 if (status != XML_STATUS_OK) {
6581 xml_failure(parser);
6582 }
6583 }
6584 }
6585 CharData_CheckXMLChars(&storage, XCS("dx")); // the <x> should be done
6586
6587 XML_ParserFree(parser);
6588 }
6589 }
6590 END_TEST
6591
6592 struct element_decl_data {
6593 XML_Parser parser;
6594 int count;
6595 };
6596
6597 static void
element_decl_counter(void * userData,const XML_Char * name,XML_Content * model)6598 element_decl_counter(void *userData, const XML_Char *name, XML_Content *model) {
6599 UNUSED_P(name);
6600 struct element_decl_data *testdata = (struct element_decl_data *)userData;
6601 testdata->count += 1;
6602 XML_FreeContentModel(testdata->parser, model);
6603 }
6604
6605 static int
external_inherited_parser(XML_Parser p,const XML_Char * context,const XML_Char * base,const XML_Char * systemId,const XML_Char * publicId)6606 external_inherited_parser(XML_Parser p, const XML_Char *context,
6607 const XML_Char *base, const XML_Char *systemId,
6608 const XML_Char *publicId) {
6609 UNUSED_P(base);
6610 UNUSED_P(systemId);
6611 UNUSED_P(publicId);
6612 const char *const pre = "<!ELEMENT document ANY>\n";
6613 const char *const start = "<!ELEMENT ";
6614 const char *const end = " ANY>\n";
6615 const char *const post = "<!ELEMENT xyz ANY>\n";
6616 const int enabled = *(int *)XML_GetUserData(p);
6617 char eeeeee[100];
6618 char spaces[100];
6619 const int fillsize = (int)sizeof(eeeeee);
6620 assert_true(fillsize == (int)sizeof(spaces));
6621 memset(eeeeee, 'e', fillsize);
6622 memset(spaces, ' ', fillsize);
6623
6624 XML_Parser parser = XML_ExternalEntityParserCreate(p, context, NULL);
6625 assert_true(parser != NULL);
6626 // pre-grow the buffer to avoid reparsing due to almost-fullness
6627 assert_true(XML_GetBuffer(parser, fillsize * 10103) != NULL);
6628
6629 struct element_decl_data testdata;
6630 testdata.parser = parser;
6631 testdata.count = 0;
6632 XML_SetUserData(parser, &testdata);
6633 XML_SetElementDeclHandler(parser, element_decl_counter);
6634
6635 enum XML_Status status;
6636 // parse the initial text
6637 status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE);
6638 if (status != XML_STATUS_OK) {
6639 xml_failure(parser);
6640 }
6641 assert_true(testdata.count == 1); // first element should be done
6642
6643 // ..and the start of the big token
6644 status = XML_Parse(parser, start, (int)strlen(start), XML_FALSE);
6645 if (status != XML_STATUS_OK) {
6646 xml_failure(parser);
6647 }
6648 assert_true(testdata.count == 1); // still just the first one
6649
6650 // try to parse lots of 'e', but the token isn't finished
6651 for (int c = 0; c < 100; ++c) {
6652 status = XML_Parse(parser, eeeeee, fillsize, XML_FALSE);
6653 if (status != XML_STATUS_OK) {
6654 xml_failure(parser);
6655 }
6656 }
6657 assert_true(testdata.count == 1); // *still* just the first one
6658
6659 // end the big token.
6660 status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE);
6661 if (status != XML_STATUS_OK) {
6662 xml_failure(parser);
6663 }
6664
6665 if (enabled) {
6666 // In general, we may need to push more data to trigger a reparse attempt,
6667 // but in this test, the data is constructed to always require it.
6668 assert_true(testdata.count == 1); // or the test is incorrect
6669 // 2x the token length should suffice; the +1 covers the start and end.
6670 for (int c = 0; c < 101; ++c) {
6671 status = XML_Parse(parser, spaces, fillsize, XML_FALSE);
6672 if (status != XML_STATUS_OK) {
6673 xml_failure(parser);
6674 }
6675 }
6676 }
6677 assert_true(testdata.count == 2); // the big token should be done
6678
6679 // parse the final text
6680 status = XML_Parse(parser, post, (int)strlen(post), XML_TRUE);
6681 if (status != XML_STATUS_OK) {
6682 xml_failure(parser);
6683 }
6684 assert_true(testdata.count == 3); // after isFinal=XML_TRUE, all must be done
6685
6686 XML_ParserFree(parser);
6687 return XML_STATUS_OK;
6688 }
6689
START_TEST(test_reparse_deferral_is_inherited)6690 START_TEST(test_reparse_deferral_is_inherited) {
6691 const char *const text
6692 = "<!DOCTYPE document SYSTEM 'something.ext'><document/>";
6693 for (int enabled = 0; enabled <= 1; ++enabled) {
6694 set_subtest("deferral=%d", enabled);
6695
6696 XML_Parser parser = XML_ParserCreate(NULL);
6697 assert_true(parser != NULL);
6698 XML_SetUserData(parser, (void *)&enabled);
6699 XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6700 // this handler creates a sub-parser and checks that its deferral behavior
6701 // is what we expected, based on the value of `enabled` (in userdata).
6702 XML_SetExternalEntityRefHandler(parser, external_inherited_parser);
6703 assert_true(XML_SetReparseDeferralEnabled(parser, enabled));
6704 if (XML_Parse(parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
6705 xml_failure(parser);
6706
6707 XML_ParserFree(parser);
6708 }
6709 }
6710 END_TEST
6711
START_TEST(test_set_reparse_deferral_on_null_parser)6712 START_TEST(test_set_reparse_deferral_on_null_parser) {
6713 assert_true(XML_SetReparseDeferralEnabled(NULL, 0) == XML_FALSE);
6714 assert_true(XML_SetReparseDeferralEnabled(NULL, 1) == XML_FALSE);
6715 assert_true(XML_SetReparseDeferralEnabled(NULL, 10) == XML_FALSE);
6716 assert_true(XML_SetReparseDeferralEnabled(NULL, 100) == XML_FALSE);
6717 assert_true(XML_SetReparseDeferralEnabled(NULL, (XML_Bool)INT_MIN)
6718 == XML_FALSE);
6719 assert_true(XML_SetReparseDeferralEnabled(NULL, (XML_Bool)INT_MAX)
6720 == XML_FALSE);
6721 }
6722 END_TEST
6723
START_TEST(test_set_reparse_deferral_on_the_fly)6724 START_TEST(test_set_reparse_deferral_on_the_fly) {
6725 const char *const pre = "<d><x attr='";
6726 const char *const end = "'></x>";
6727 char iiiiii[100];
6728 const int fillsize = (int)sizeof(iiiiii);
6729 memset(iiiiii, 'i', fillsize);
6730
6731 XML_Parser parser = XML_ParserCreate(NULL);
6732 assert_true(parser != NULL);
6733 assert_true(XML_SetReparseDeferralEnabled(parser, XML_TRUE));
6734
6735 CharData storage;
6736 CharData_Init(&storage);
6737 XML_SetUserData(parser, &storage);
6738 XML_SetStartElementHandler(parser, start_element_event_handler);
6739
6740 enum XML_Status status;
6741 // parse the start text
6742 status = XML_Parse(parser, pre, (int)strlen(pre), XML_FALSE);
6743 if (status != XML_STATUS_OK) {
6744 xml_failure(parser);
6745 }
6746 CharData_CheckXMLChars(&storage, XCS("d")); // first element should be done
6747
6748 // try to parse some 'i', but the token isn't finished
6749 status = XML_Parse(parser, iiiiii, fillsize, XML_FALSE);
6750 if (status != XML_STATUS_OK) {
6751 xml_failure(parser);
6752 }
6753 CharData_CheckXMLChars(&storage, XCS("d")); // *still* just the first one
6754
6755 // end the <x> token.
6756 status = XML_Parse(parser, end, (int)strlen(end), XML_FALSE);
6757 if (status != XML_STATUS_OK) {
6758 xml_failure(parser);
6759 }
6760 CharData_CheckXMLChars(&storage, XCS("d")); // not yet.
6761
6762 // now change the heuristic setting and add *no* data
6763 assert_true(XML_SetReparseDeferralEnabled(parser, XML_FALSE));
6764 // we avoid isFinal=XML_TRUE, because that would force-bypass the heuristic.
6765 status = XML_Parse(parser, "", 0, XML_FALSE);
6766 if (status != XML_STATUS_OK) {
6767 xml_failure(parser);
6768 }
6769 CharData_CheckXMLChars(&storage, XCS("dx"));
6770
6771 XML_ParserFree(parser);
6772 }
6773 END_TEST
6774
START_TEST(test_set_bad_reparse_option)6775 START_TEST(test_set_bad_reparse_option) {
6776 XML_Parser parser = XML_ParserCreate(NULL);
6777 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 2));
6778 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 3));
6779 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 99));
6780 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 127));
6781 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 128));
6782 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 129));
6783 assert_true(XML_FALSE == XML_SetReparseDeferralEnabled(parser, 255));
6784 assert_true(XML_TRUE == XML_SetReparseDeferralEnabled(parser, 0));
6785 assert_true(XML_TRUE == XML_SetReparseDeferralEnabled(parser, 1));
6786 XML_ParserFree(parser);
6787 }
6788 END_TEST
6789
6790 static size_t g_totalAlloc = 0;
6791 static size_t g_biggestAlloc = 0;
6792
6793 static void *
counting_realloc(void * ptr,size_t size)6794 counting_realloc(void *ptr, size_t size) {
6795 g_totalAlloc += size;
6796 if (size > g_biggestAlloc) {
6797 g_biggestAlloc = size;
6798 }
6799 return realloc(ptr, size);
6800 }
6801
6802 static void *
counting_malloc(size_t size)6803 counting_malloc(size_t size) {
6804 return counting_realloc(NULL, size);
6805 }
6806
START_TEST(test_bypass_heuristic_when_close_to_bufsize)6807 START_TEST(test_bypass_heuristic_when_close_to_bufsize) {
6808 if (g_chunkSize != 0) {
6809 // this test does not use SINGLE_BYTES, because it depends on very precise
6810 // buffer fills.
6811 return;
6812 }
6813 if (! g_reparseDeferralEnabledDefault) {
6814 return; // this test is irrelevant when the deferral heuristic is disabled.
6815 }
6816
6817 const int document_length = 65536;
6818 char *const document = malloc(document_length);
6819 assert_true(document != NULL);
6820
6821 const XML_Memory_Handling_Suite memfuncs = {
6822 counting_malloc,
6823 counting_realloc,
6824 free,
6825 };
6826
6827 const int leading_list[] = {0, 3, 61, 96, 400, 401, 4000, 4010, 4099, -1};
6828 const int bigtoken_list[] = {3000, 4000, 4001, 4096, 4099, 5000, 20000, -1};
6829 const int fillsize_list[] = {131, 256, 399, 400, 401, 1025, 4099, 4321, -1};
6830
6831 for (const int *leading = leading_list; *leading >= 0; leading++) {
6832 for (const int *bigtoken = bigtoken_list; *bigtoken >= 0; bigtoken++) {
6833 for (const int *fillsize = fillsize_list; *fillsize >= 0; fillsize++) {
6834 set_subtest("leading=%d bigtoken=%d fillsize=%d", *leading, *bigtoken,
6835 *fillsize);
6836 // start by checking that the test looks reasonably valid
6837 assert_true(*leading + *bigtoken <= document_length);
6838
6839 // put 'x' everywhere; some will be overwritten by elements.
6840 memset(document, 'x', document_length);
6841 // maybe add an initial tag
6842 if (*leading) {
6843 assert_true(*leading >= 3); // or the test case is invalid
6844 memcpy(document, "<a>", 3);
6845 }
6846 // add the large token
6847 document[*leading + 0] = '<';
6848 document[*leading + 1] = 'b';
6849 memset(&document[*leading + 2], ' ', *bigtoken - 2); // a spacy token
6850 document[*leading + *bigtoken - 1] = '>';
6851
6852 // 1 for 'b', plus 1 or 0 depending on the presence of 'a'
6853 const int expected_elem_total = 1 + (*leading ? 1 : 0);
6854
6855 XML_Parser parser = XML_ParserCreate_MM(NULL, &memfuncs, NULL);
6856 assert_true(parser != NULL);
6857
6858 CharData storage;
6859 CharData_Init(&storage);
6860 XML_SetUserData(parser, &storage);
6861 XML_SetStartElementHandler(parser, start_element_event_handler);
6862
6863 g_biggestAlloc = 0;
6864 g_totalAlloc = 0;
6865 int offset = 0;
6866 // fill data until the big token is covered (but not necessarily parsed)
6867 while (offset < *leading + *bigtoken) {
6868 assert_true(offset + *fillsize <= document_length);
6869 const enum XML_Status status
6870 = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
6871 if (status != XML_STATUS_OK) {
6872 xml_failure(parser);
6873 }
6874 offset += *fillsize;
6875 }
6876 // Now, check that we've had a buffer allocation that could fit the
6877 // context bytes and our big token. In order to detect a special case,
6878 // we need to know how many bytes of our big token were included in the
6879 // first push that contained _any_ bytes of the big token:
6880 const int bigtok_first_chunk_bytes = *fillsize - (*leading % *fillsize);
6881 if (bigtok_first_chunk_bytes >= *bigtoken && XML_CONTEXT_BYTES == 0) {
6882 // Special case: we aren't saving any context, and the whole big token
6883 // was covered by a single fill, so Expat may have parsed directly
6884 // from our input pointer, without allocating an internal buffer.
6885 } else if (*leading < XML_CONTEXT_BYTES) {
6886 assert_true(g_biggestAlloc >= *leading + (size_t)*bigtoken);
6887 } else {
6888 assert_true(g_biggestAlloc >= XML_CONTEXT_BYTES + (size_t)*bigtoken);
6889 }
6890 // fill data until the big token is actually parsed
6891 while (storage.count < expected_elem_total) {
6892 const size_t alloc_before = g_totalAlloc;
6893 assert_true(offset + *fillsize <= document_length);
6894 const enum XML_Status status
6895 = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
6896 if (status != XML_STATUS_OK) {
6897 xml_failure(parser);
6898 }
6899 offset += *fillsize;
6900 // since all the bytes of the big token are already in the buffer,
6901 // the bufsize ceiling should make us finish its parsing without any
6902 // further buffer allocations. We assume that there will be no other
6903 // large allocations in this test.
6904 assert_true(g_totalAlloc - alloc_before < 4096);
6905 }
6906 // test-the-test: was our alloc even called?
6907 assert_true(g_totalAlloc > 0);
6908 // test-the-test: there shouldn't be any extra start elements
6909 assert_true(storage.count == expected_elem_total);
6910
6911 XML_ParserFree(parser);
6912 }
6913 }
6914 }
6915 free(document);
6916 }
6917 END_TEST
6918
START_TEST(test_varying_buffer_fills)6919 START_TEST(test_varying_buffer_fills) {
6920 const int KiB = 1024;
6921 const int MiB = 1024 * KiB;
6922 const int document_length = 16 * MiB;
6923 const int big = 7654321; // arbitrarily chosen between 4 and 8 MiB
6924
6925 if (g_chunkSize != 0) {
6926 return; // this test is slow, and doesn't use _XML_Parse_SINGLE_BYTES().
6927 }
6928
6929 char *const document = malloc(document_length);
6930 assert_true(document != NULL);
6931 memset(document, 'x', document_length);
6932 document[0] = '<';
6933 document[1] = 't';
6934 memset(&document[2], ' ', big - 2); // a very spacy token
6935 document[big - 1] = '>';
6936
6937 // Each testcase is a list of buffer fill sizes, terminated by a value < 0.
6938 // When reparse deferral is enabled, the final (negated) value is the expected
6939 // maximum number of bytes scanned in parse attempts.
6940 const int testcases[][30] = {
6941 {8 * MiB, -8 * MiB},
6942 {4 * MiB, 4 * MiB, -12 * MiB}, // try at 4MB, then 8MB = 12 MB total
6943 // zero-size fills shouldn't trigger the bypass
6944 {4 * MiB, 0, 4 * MiB, -12 * MiB},
6945 {4 * MiB, 0, 0, 4 * MiB, -12 * MiB},
6946 {4 * MiB, 0, 1 * MiB, 0, 3 * MiB, -12 * MiB},
6947 // try to hit the buffer ceiling only once (at the end)
6948 {4 * MiB, 2 * MiB, 1 * MiB, 512 * KiB, 256 * KiB, 256 * KiB, -12 * MiB},
6949 // try to hit the same buffer ceiling multiple times
6950 {4 * MiB + 1, 2 * MiB, 1 * MiB, 512 * KiB, -25 * MiB},
6951
6952 // try to hit every ceiling, by always landing 1K shy of the buffer size
6953 {1 * KiB, 2 * KiB, 4 * KiB, 8 * KiB, 16 * KiB, 32 * KiB, 64 * KiB,
6954 128 * KiB, 256 * KiB, 512 * KiB, 1 * MiB, 2 * MiB, 4 * MiB, -16 * MiB},
6955
6956 // try to avoid every ceiling, by always landing 1B past the buffer size
6957 // the normal 2x heuristic threshold still forces parse attempts.
6958 {2 * KiB + 1, // will attempt 2KiB + 1 ==> total 2KiB + 1
6959 2 * KiB, 4 * KiB, // will attempt 8KiB + 1 ==> total 10KiB + 2
6960 8 * KiB, 16 * KiB, // will attempt 32KiB + 1 ==> total 42KiB + 3
6961 32 * KiB, 64 * KiB, // will attempt 128KiB + 1 ==> total 170KiB + 4
6962 128 * KiB, 256 * KiB, // will attempt 512KiB + 1 ==> total 682KiB + 5
6963 512 * KiB, 1 * MiB, // will attempt 2MiB + 1 ==> total 2M + 682K + 6
6964 2 * MiB, 4 * MiB, // will attempt 8MiB + 1 ==> total 10M + 682K + 7
6965 -(10 * MiB + 682 * KiB + 7)},
6966 // try to avoid every ceiling again, except on our last fill.
6967 {2 * KiB + 1, // will attempt 2KiB + 1 ==> total 2KiB + 1
6968 2 * KiB, 4 * KiB, // will attempt 8KiB + 1 ==> total 10KiB + 2
6969 8 * KiB, 16 * KiB, // will attempt 32KiB + 1 ==> total 42KiB + 3
6970 32 * KiB, 64 * KiB, // will attempt 128KiB + 1 ==> total 170KiB + 4
6971 128 * KiB, 256 * KiB, // will attempt 512KiB + 1 ==> total 682KiB + 5
6972 512 * KiB, 1 * MiB, // will attempt 2MiB + 1 ==> total 2M + 682K + 6
6973 2 * MiB, 4 * MiB - 1, // will attempt 8MiB ==> total 10M + 682K + 6
6974 -(10 * MiB + 682 * KiB + 6)},
6975
6976 // try to hit ceilings on the way multiple times
6977 {512 * KiB + 1, 256 * KiB, 128 * KiB, 128 * KiB - 1, // 1 MiB buffer
6978 512 * KiB + 1, 256 * KiB, 128 * KiB, 128 * KiB - 1, // 2 MiB buffer
6979 1 * MiB + 1, 512 * KiB, 256 * KiB, 256 * KiB - 1, // 4 MiB buffer
6980 2 * MiB + 1, 1 * MiB, 512 * KiB, // 8 MiB buffer
6981 // we'll make a parse attempt at every parse call
6982 -(45 * MiB + 12)},
6983 };
6984 const int testcount = sizeof(testcases) / sizeof(testcases[0]);
6985 for (int test_i = 0; test_i < testcount; test_i++) {
6986 const int *fillsize = testcases[test_i];
6987 set_subtest("#%d {%d %d %d %d ...}", test_i, fillsize[0], fillsize[1],
6988 fillsize[2], fillsize[3]);
6989 XML_Parser parser = XML_ParserCreate(NULL);
6990 assert_true(parser != NULL);
6991
6992 CharData storage;
6993 CharData_Init(&storage);
6994 XML_SetUserData(parser, &storage);
6995 XML_SetStartElementHandler(parser, start_element_event_handler);
6996
6997 g_bytesScanned = 0;
6998 int worstcase_bytes = 0; // sum of (buffered bytes at each XML_Parse call)
6999 int offset = 0;
7000 while (*fillsize >= 0) {
7001 assert_true(offset + *fillsize <= document_length); // or test is invalid
7002 const enum XML_Status status
7003 = XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
7004 if (status != XML_STATUS_OK) {
7005 xml_failure(parser);
7006 }
7007 offset += *fillsize;
7008 fillsize++;
7009 assert_true(offset <= INT_MAX - worstcase_bytes); // avoid overflow
7010 worstcase_bytes += offset; // we might've tried to parse all pending bytes
7011 }
7012 assert_true(storage.count == 1); // the big token should've been parsed
7013 assert_true(g_bytesScanned > 0); // test-the-test: does our counter work?
7014 if (g_reparseDeferralEnabledDefault) {
7015 // heuristic is enabled; some XML_Parse calls may have deferred reparsing
7016 const unsigned max_bytes_scanned = -*fillsize;
7017 if (g_bytesScanned > max_bytes_scanned) {
7018 fprintf(stderr,
7019 "bytes scanned in parse attempts: actual=%u limit=%u \n",
7020 g_bytesScanned, max_bytes_scanned);
7021 fail("too many bytes scanned in parse attempts");
7022 }
7023 }
7024 assert_true(g_bytesScanned <= (unsigned)worstcase_bytes);
7025
7026 XML_ParserFree(parser);
7027 }
7028 free(document);
7029 }
7030 END_TEST
7031
START_TEST(test_empty_ext_param_entity_in_value)7032 START_TEST(test_empty_ext_param_entity_in_value) {
7033 const char *text = "<!DOCTYPE r SYSTEM \"ext.dtd\"><r/>";
7034 ExtOption options[] = {
7035 {XCS("ext.dtd"), "<!ENTITY % pe SYSTEM \"empty\">"
7036 "<!ENTITY ge \"%pe;\">"},
7037 {XCS("empty"), ""},
7038 {NULL, NULL},
7039 };
7040
7041 XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7042 XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
7043 XML_SetUserData(g_parser, options);
7044 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7045 == XML_STATUS_ERROR)
7046 xml_failure(g_parser);
7047 }
7048 END_TEST
7049
7050 void
make_basic_test_case(Suite * s)7051 make_basic_test_case(Suite *s) {
7052 TCase *tc_basic = tcase_create("basic tests");
7053
7054 suite_add_tcase(s, tc_basic);
7055 tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
7056
7057 tcase_add_test(tc_basic, test_nul_byte);
7058 tcase_add_test(tc_basic, test_u0000_char);
7059 tcase_add_test(tc_basic, test_siphash_self);
7060 tcase_add_test(tc_basic, test_siphash_spec);
7061 tcase_add_test(tc_basic, test_bom_utf8);
7062 tcase_add_test(tc_basic, test_bom_utf16_be);
7063 tcase_add_test(tc_basic, test_bom_utf16_le);
7064 tcase_add_test(tc_basic, test_nobom_utf16_le);
7065 tcase_add_test(tc_basic, test_hash_collision);
7066 tcase_add_test(tc_basic, test_hash_salt_setter);
7067 tcase_add_test(tc_basic, test_illegal_utf8);
7068 tcase_add_test(tc_basic, test_utf8_auto_align);
7069 tcase_add_test(tc_basic, test_utf16);
7070 tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
7071 tcase_add_test(tc_basic, test_not_utf16);
7072 tcase_add_test(tc_basic, test_bad_encoding);
7073 tcase_add_test(tc_basic, test_latin1_umlauts);
7074 tcase_add_test(tc_basic, test_long_utf8_character);
7075 tcase_add_test(tc_basic, test_long_latin1_attribute);
7076 tcase_add_test(tc_basic, test_long_ascii_attribute);
7077 /* Regression test for SF bug #491986. */
7078 tcase_add_test(tc_basic, test_danish_latin1);
7079 /* Regression test for SF bug #514281. */
7080 tcase_add_test(tc_basic, test_french_charref_hexidecimal);
7081 tcase_add_test(tc_basic, test_french_charref_decimal);
7082 tcase_add_test(tc_basic, test_french_latin1);
7083 tcase_add_test(tc_basic, test_french_utf8);
7084 tcase_add_test(tc_basic, test_utf8_false_rejection);
7085 tcase_add_test(tc_basic, test_line_number_after_parse);
7086 tcase_add_test(tc_basic, test_column_number_after_parse);
7087 tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
7088 tcase_add_test(tc_basic, test_line_number_after_error);
7089 tcase_add_test(tc_basic, test_column_number_after_error);
7090 tcase_add_test(tc_basic, test_really_long_lines);
7091 tcase_add_test(tc_basic, test_really_long_encoded_lines);
7092 tcase_add_test(tc_basic, test_end_element_events);
7093 tcase_add_test(tc_basic, test_helper_is_whitespace_normalized);
7094 tcase_add_test(tc_basic, test_attr_whitespace_normalization);
7095 tcase_add_test(tc_basic, test_xmldecl_misplaced);
7096 tcase_add_test(tc_basic, test_xmldecl_invalid);
7097 tcase_add_test(tc_basic, test_xmldecl_missing_attr);
7098 tcase_add_test(tc_basic, test_xmldecl_missing_value);
7099 tcase_add_test(tc_basic, test_xmldecl_empty_version);
7100 tcase_add_test(tc_basic, test_xmldecl_wrong_version_number);
7101 tcase_add_test(tc_basic, test_xmldecl_accepts_1_x_version);
7102 tcase_add_test__if_xml_ge(tc_basic, test_unknown_encoding_internal_entity);
7103 tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
7104 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding);
7105 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_no_handler);
7106 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_bom);
7107 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding);
7108 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding_2);
7109 tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset);
7110 tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
7111 tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
7112 tcase_add_test(tc_basic,
7113 test_wfc_undeclared_entity_with_external_subset_standalone);
7114 tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone);
7115 tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
7116 tcase_add_test(tc_basic, test_not_standalone_handler_reject);
7117 tcase_add_test(tc_basic, test_not_standalone_handler_accept);
7118 tcase_add_test(tc_basic, test_entity_start_tag_level_greater_than_one);
7119 tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs);
7120 tcase_add_test(tc_basic, test_no_indirectly_recursive_entity_refs);
7121 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
7122 tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling);
7123 tcase_add_test(tc_basic, test_dtd_attr_handling);
7124 tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
7125 tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
7126 tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
7127 tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
7128 tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls);
7129 tcase_add_test(tc_basic, test_good_cdata_ascii);
7130 tcase_add_test(tc_basic, test_good_cdata_utf16);
7131 tcase_add_test(tc_basic, test_good_cdata_utf16_le);
7132 tcase_add_test(tc_basic, test_long_cdata_utf16);
7133 tcase_add_test(tc_basic, test_multichar_cdata_utf16);
7134 tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
7135 tcase_add_test(tc_basic, test_utf16_surrogate_pairs);
7136 tcase_add_test(tc_basic, test_bad_cdata);
7137 tcase_add_test(tc_basic, test_bad_cdata_utf16);
7138 tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
7139 tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
7140 tcase_add_test(tc_basic, test_memory_allocation);
7141 tcase_add_test__if_xml_ge(tc_basic, test_default_current);
7142 tcase_add_test(tc_basic, test_dtd_elements);
7143 tcase_add_test(tc_basic, test_dtd_elements_nesting);
7144 tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
7145 tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone);
7146 tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd);
7147 tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_with_doctype);
7148 tcase_add_test__ifdef_xml_dtd(tc_basic,
7149 test_foreign_dtd_without_external_subset);
7150 tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
7151 tcase_add_test(tc_basic, test_set_base);
7152 tcase_add_test(tc_basic, test_attributes);
7153 tcase_add_test(tc_basic, test_duplicate_cdata_attribute);
7154 tcase_add_test(tc_basic, test_duplicate_id_attribute_1);
7155 tcase_add_test(tc_basic, test_duplicate_id_attribute_2);
7156 tcase_add_test(tc_basic, test_duplicate_cdata_attribute_multiple_attlistdecl);
7157 tcase_add_test(tc_basic,
7158 test_duplicate_cdata_attribute_multiple_attlistdecl_2);
7159 tcase_add_test(tc_basic,
7160 test_duplicate_cdata_attribute_multiple_attlistdecl_3);
7161 tcase_add_test(tc_basic, test_duplicate_id_attribute_multiple_attlistdecl);
7162 tcase_add_test__if_xml_ge(tc_basic, test_default_attr_index_after_dtd_copy);
7163 tcase_add_test__if_xml_ge(tc_basic, test_reset_in_entity);
7164 tcase_add_test(tc_basic, test_resume_invalid_parse);
7165 tcase_add_test(tc_basic, test_resume_resuspended);
7166 tcase_add_test(tc_basic, test_cdata_default);
7167 tcase_add_test(tc_basic, test_subordinate_reset);
7168 tcase_add_test(tc_basic, test_subordinate_suspend);
7169 tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_suspend);
7170 tcase_add_test__if_xml_ge(tc_basic, test_subordinate_xdecl_abort);
7171 tcase_add_test__ifdef_xml_dtd(tc_basic,
7172 test_ext_entity_invalid_suspended_parse);
7173 tcase_add_test(tc_basic, test_explicit_encoding);
7174 tcase_add_test(tc_basic, test_trailing_cr);
7175 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_trailing_cr);
7176 tcase_add_test(tc_basic, test_trailing_rsqb);
7177 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_trailing_rsqb);
7178 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_good_cdata);
7179 tcase_add_test__ifdef_xml_dtd(tc_basic, test_user_parameters);
7180 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_ref_parameter);
7181 tcase_add_test(tc_basic, test_empty_parse);
7182 tcase_add_test(tc_basic, test_negative_len_parse);
7183 tcase_add_test(tc_basic, test_negative_len_parse_buffer);
7184 tcase_add_test(tc_basic, test_get_buffer_1);
7185 tcase_add_test(tc_basic, test_get_buffer_2);
7186 #if XML_CONTEXT_BYTES > 0
7187 tcase_add_test(tc_basic, test_get_buffer_3_overflow);
7188 #endif
7189 tcase_add_test(tc_basic, test_buffer_can_grow_to_max);
7190 tcase_add_test(tc_basic, test_getbuffer_allocates_on_zero_len);
7191 tcase_add_test(tc_basic, test_byte_info_at_end);
7192 tcase_add_test(tc_basic, test_byte_info_at_error);
7193 tcase_add_test(tc_basic, test_byte_info_at_cdata);
7194 tcase_add_test(tc_basic, test_predefined_entities);
7195 tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_tag_in_dtd);
7196 tcase_add_test(tc_basic, test_not_predefined_entities);
7197 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section);
7198 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16);
7199 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16_be);
7200 tcase_add_test__ifdef_xml_dtd(tc_basic, test_bad_ignore_section);
7201 tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_bom_consumed);
7202 tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_entity_values);
7203 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_not_standalone);
7204 tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_value_abort);
7205 tcase_add_test(tc_basic, test_bad_public_doctype);
7206 tcase_add_test(tc_basic, test_attribute_enum_value);
7207 tcase_add_test(tc_basic, test_predefined_entity_redefinition);
7208 tcase_add_test__ifdef_xml_dtd(tc_basic, test_dtd_stop_processing);
7209 tcase_add_test(tc_basic, test_public_notation_no_sysid);
7210 tcase_add_test(tc_basic, test_nested_groups);
7211 tcase_add_test(tc_basic, test_group_choice);
7212 tcase_add_test(tc_basic, test_standalone_parameter_entity);
7213 tcase_add_test__ifdef_xml_dtd(tc_basic, test_skipped_parameter_entity);
7214 tcase_add_test__ifdef_xml_dtd(tc_basic,
7215 test_recursive_external_parameter_entity);
7216 tcase_add_test__ifdef_xml_dtd(tc_basic,
7217 test_recursive_external_parameter_entity_2);
7218 tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
7219 tcase_add_test(tc_basic, test_suspend_xdecl);
7220 tcase_add_test(tc_basic, test_abort_epilog);
7221 tcase_add_test(tc_basic, test_abort_epilog_2);
7222 tcase_add_test(tc_basic, test_suspend_epilog);
7223 tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag);
7224 tcase_add_test(tc_basic, test_unfinished_epilog);
7225 tcase_add_test(tc_basic, test_partial_char_in_epilog);
7226 tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_internal_entity);
7227 tcase_add_test__ifdef_xml_dtd(tc_basic,
7228 test_suspend_resume_internal_entity_issue_629);
7229 tcase_add_test__ifdef_xml_dtd(tc_basic, test_resume_entity_with_syntax_error);
7230 tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_parameter_entity);
7231 tcase_add_test(tc_basic, test_restart_on_error);
7232 tcase_add_test(tc_basic, test_reject_lt_in_attribute_value);
7233 tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value);
7234 tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
7235 tcase_add_test(tc_basic, test_standalone_internal_entity);
7236 tcase_add_test(tc_basic, test_skipped_external_entity);
7237 tcase_add_test__ifdef_xml_dtd(
7238 tc_basic, test_scaff_index_shared_across_external_entity_parser);
7239 tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
7240 tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
7241 tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
7242 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity);
7243 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_2);
7244 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_3);
7245 tcase_add_test__if_xml_ge(tc_basic, test_invalid_character_entity_4);
7246 tcase_add_test(tc_basic, test_pi_handled_in_default);
7247 tcase_add_test(tc_basic, test_comment_handled_in_default);
7248 tcase_add_test(tc_basic, test_pi_yml);
7249 tcase_add_test(tc_basic, test_pi_xnl);
7250 tcase_add_test(tc_basic, test_pi_xmm);
7251 tcase_add_test(tc_basic, test_utf16_pi);
7252 tcase_add_test(tc_basic, test_utf16_be_pi);
7253 tcase_add_test(tc_basic, test_utf16_be_comment);
7254 tcase_add_test(tc_basic, test_utf16_le_comment);
7255 tcase_add_test(tc_basic, test_missing_encoding_conversion_fn);
7256 tcase_add_test(tc_basic, test_failing_encoding_conversion_fn);
7257 tcase_add_test(tc_basic, test_unknown_encoding_success);
7258 tcase_add_test(tc_basic, test_unknown_encoding_bad_name);
7259 tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2);
7260 tcase_add_test(tc_basic, test_unknown_encoding_long_name_1);
7261 tcase_add_test(tc_basic, test_unknown_encoding_long_name_2);
7262 tcase_add_test(tc_basic, test_invalid_unknown_encoding);
7263 tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok);
7264 tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail);
7265 tcase_add_test(tc_basic, test_unknown_encoding_invalid_length);
7266 tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit);
7267 tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
7268 tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
7269 tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
7270 tcase_add_test(tc_basic, test_unknown_encoding_user_data_primary);
7271 tcase_add_test(tc_basic, test_unknown_encoding_user_data_secondary);
7272 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom);
7273 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom);
7274 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16le_bom2);
7275 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_latin1_utf16be_bom2);
7276 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_be);
7277 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_le);
7278 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf16_unknown);
7279 tcase_add_test__if_xml_ge(tc_basic, test_ext_entity_utf8_non_bom);
7280 tcase_add_test(tc_basic, test_utf8_in_cdata_section);
7281 tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
7282 tcase_add_test(tc_basic, test_utf8_in_start_tags);
7283 tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
7284 tcase_add_test(tc_basic, test_utf16_attribute);
7285 tcase_add_test(tc_basic, test_utf16_second_attr);
7286 tcase_add_test(tc_basic, test_attr_after_solidus);
7287 tcase_add_test__ifdef_xml_dtd(tc_basic, test_utf16_pe);
7288 tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
7289 tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
7290 tcase_add_test(tc_basic, test_bad_doctype);
7291 tcase_add_test(tc_basic, test_bad_doctype_utf8);
7292 tcase_add_test(tc_basic, test_bad_doctype_utf16);
7293 tcase_add_test(tc_basic, test_bad_doctype_plus);
7294 tcase_add_test(tc_basic, test_bad_doctype_star);
7295 tcase_add_test(tc_basic, test_bad_doctype_query);
7296 tcase_add_test__ifdef_xml_dtd(tc_basic, test_unknown_encoding_bad_ignore);
7297 tcase_add_test(tc_basic, test_entity_in_utf16_be_attr);
7298 tcase_add_test(tc_basic, test_entity_in_utf16_le_attr);
7299 tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_be);
7300 tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_le);
7301 tcase_add_test(tc_basic, test_short_doctype);
7302 tcase_add_test(tc_basic, test_short_doctype_2);
7303 tcase_add_test(tc_basic, test_short_doctype_3);
7304 tcase_add_test(tc_basic, test_long_doctype);
7305 tcase_add_test(tc_basic, test_bad_entity);
7306 tcase_add_test(tc_basic, test_bad_entity_2);
7307 tcase_add_test(tc_basic, test_bad_entity_3);
7308 tcase_add_test(tc_basic, test_bad_entity_4);
7309 tcase_add_test(tc_basic, test_bad_notation);
7310 tcase_add_test(tc_basic, test_default_doctype_handler);
7311 tcase_add_test(tc_basic, test_empty_element_abort);
7312 tcase_add_test__ifdef_xml_dtd(tc_basic,
7313 test_pool_integrity_with_unfinished_attr);
7314 tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_ext_param_entity_in_value);
7315 tcase_add_test__if_xml_ge(tc_basic, test_entity_ref_no_elements);
7316 tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_entity);
7317 tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_attribute_entity);
7318 tcase_add_test__if_xml_ge(tc_basic,
7319 test_deep_nested_entity_delayed_interpretation);
7320 tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend);
7321 tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend_2);
7322 tcase_add_test(tc_basic, test_big_tokens_scale_linearly);
7323 tcase_add_test(tc_basic, test_set_reparse_deferral);
7324 tcase_add_test(tc_basic, test_reparse_deferral_is_inherited);
7325 tcase_add_test(tc_basic, test_set_reparse_deferral_on_null_parser);
7326 tcase_add_test(tc_basic, test_set_reparse_deferral_on_the_fly);
7327 tcase_add_test(tc_basic, test_set_bad_reparse_option);
7328 tcase_add_test(tc_basic, test_bypass_heuristic_when_close_to_bufsize);
7329 tcase_add_test(tc_basic, test_varying_buffer_fills);
7330 }
7331