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