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