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