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