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