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