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