1bd8f1dc3Sbluhm /* Tests in the "miscellaneous" test case for the Expat test suite
2bd8f1dc3Sbluhm __ __ _
3bd8f1dc3Sbluhm ___\ \/ /_ __ __ _| |_
4bd8f1dc3Sbluhm / _ \\ /| '_ \ / _` | __|
5bd8f1dc3Sbluhm | __// \| |_) | (_| | |_
6bd8f1dc3Sbluhm \___/_/\_\ .__/ \__,_|\__|
7bd8f1dc3Sbluhm |_| XML parser
8bd8f1dc3Sbluhm
9bd8f1dc3Sbluhm Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
10bd8f1dc3Sbluhm Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
11bd8f1dc3Sbluhm Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
12bd8f1dc3Sbluhm Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
13bd8f1dc3Sbluhm Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
14bd8f1dc3Sbluhm Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
15bd8f1dc3Sbluhm Copyright (c) 2017 Joe Orton <jorton@redhat.com>
16bd8f1dc3Sbluhm Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
17bd8f1dc3Sbluhm Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it>
18bd8f1dc3Sbluhm Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
19bd8f1dc3Sbluhm Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
20bd8f1dc3Sbluhm Copyright (c) 2021 Donghee Na <donghee.na@python.org>
21bd8f1dc3Sbluhm Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
22bd8f1dc3Sbluhm Licensed under the MIT license:
23bd8f1dc3Sbluhm
24bd8f1dc3Sbluhm Permission is hereby granted, free of charge, to any person obtaining
25bd8f1dc3Sbluhm a copy of this software and associated documentation files (the
26bd8f1dc3Sbluhm "Software"), to deal in the Software without restriction, including
27bd8f1dc3Sbluhm without limitation the rights to use, copy, modify, merge, publish,
28bd8f1dc3Sbluhm distribute, sublicense, and/or sell copies of the Software, and to permit
29bd8f1dc3Sbluhm persons to whom the Software is furnished to do so, subject to the
30bd8f1dc3Sbluhm following conditions:
31bd8f1dc3Sbluhm
32bd8f1dc3Sbluhm The above copyright notice and this permission notice shall be included
33bd8f1dc3Sbluhm in all copies or substantial portions of the Software.
34bd8f1dc3Sbluhm
35bd8f1dc3Sbluhm THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
36bd8f1dc3Sbluhm EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37bd8f1dc3Sbluhm MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
38bd8f1dc3Sbluhm NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
39bd8f1dc3Sbluhm DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
40bd8f1dc3Sbluhm OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
41bd8f1dc3Sbluhm USE OR OTHER DEALINGS IN THE SOFTWARE.
42bd8f1dc3Sbluhm */
43bd8f1dc3Sbluhm
44bd8f1dc3Sbluhm #if defined(NDEBUG)
45bd8f1dc3Sbluhm # undef NDEBUG /* because test suite relies on assert(...) at the moment */
46bd8f1dc3Sbluhm #endif
47bd8f1dc3Sbluhm
48bd8f1dc3Sbluhm #include <assert.h>
49bd8f1dc3Sbluhm #include <string.h>
50bd8f1dc3Sbluhm
51bd8f1dc3Sbluhm #include "expat_config.h"
52bd8f1dc3Sbluhm
53bd8f1dc3Sbluhm #include "expat.h"
54bd8f1dc3Sbluhm #include "internal.h"
55bd8f1dc3Sbluhm #include "minicheck.h"
56bd8f1dc3Sbluhm #include "memcheck.h"
57bd8f1dc3Sbluhm #include "common.h"
58bd8f1dc3Sbluhm #include "ascii.h" /* for ASCII_xxx */
59bd8f1dc3Sbluhm #include "handlers.h"
60bd8f1dc3Sbluhm #include "misc_tests.h"
61bd8f1dc3Sbluhm
62bd8f1dc3Sbluhm /* Test that a failure to allocate the parser structure fails gracefully */
START_TEST(test_misc_alloc_create_parser)63bd8f1dc3Sbluhm START_TEST(test_misc_alloc_create_parser) {
64bd8f1dc3Sbluhm XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
65bd8f1dc3Sbluhm unsigned int i;
66bd8f1dc3Sbluhm const unsigned int max_alloc_count = 10;
67bd8f1dc3Sbluhm
68bd8f1dc3Sbluhm /* Something this simple shouldn't need more than 10 allocations */
69bd8f1dc3Sbluhm for (i = 0; i < max_alloc_count; i++) {
70bd8f1dc3Sbluhm g_allocation_count = i;
71bd8f1dc3Sbluhm g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
72bd8f1dc3Sbluhm if (g_parser != NULL)
73bd8f1dc3Sbluhm break;
74bd8f1dc3Sbluhm }
75bd8f1dc3Sbluhm if (i == 0)
76bd8f1dc3Sbluhm fail("Parser unexpectedly ignored failing allocator");
77bd8f1dc3Sbluhm else if (i == max_alloc_count)
78bd8f1dc3Sbluhm fail("Parser not created with max allocation count");
79bd8f1dc3Sbluhm }
80bd8f1dc3Sbluhm END_TEST
81bd8f1dc3Sbluhm
82bd8f1dc3Sbluhm /* Test memory allocation failures for a parser with an encoding */
START_TEST(test_misc_alloc_create_parser_with_encoding)83bd8f1dc3Sbluhm START_TEST(test_misc_alloc_create_parser_with_encoding) {
84bd8f1dc3Sbluhm XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
85bd8f1dc3Sbluhm unsigned int i;
86bd8f1dc3Sbluhm const unsigned int max_alloc_count = 10;
87bd8f1dc3Sbluhm
88bd8f1dc3Sbluhm /* Try several levels of allocation */
89bd8f1dc3Sbluhm for (i = 0; i < max_alloc_count; i++) {
90bd8f1dc3Sbluhm g_allocation_count = i;
91bd8f1dc3Sbluhm g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL);
92bd8f1dc3Sbluhm if (g_parser != NULL)
93bd8f1dc3Sbluhm break;
94bd8f1dc3Sbluhm }
95bd8f1dc3Sbluhm if (i == 0)
96bd8f1dc3Sbluhm fail("Parser ignored failing allocator");
97bd8f1dc3Sbluhm else if (i == max_alloc_count)
98bd8f1dc3Sbluhm fail("Parser not created with max allocation count");
99bd8f1dc3Sbluhm }
100bd8f1dc3Sbluhm END_TEST
101bd8f1dc3Sbluhm
102bd8f1dc3Sbluhm /* Test that freeing a NULL parser doesn't cause an explosion.
103bd8f1dc3Sbluhm * (Not actually tested anywhere else)
104bd8f1dc3Sbluhm */
START_TEST(test_misc_null_parser)105bd8f1dc3Sbluhm START_TEST(test_misc_null_parser) {
106bd8f1dc3Sbluhm XML_ParserFree(NULL);
107bd8f1dc3Sbluhm }
108bd8f1dc3Sbluhm END_TEST
109bd8f1dc3Sbluhm
110bd8f1dc3Sbluhm #if defined(__has_feature)
111bd8f1dc3Sbluhm # if __has_feature(undefined_behavior_sanitizer)
112bd8f1dc3Sbluhm # define EXPAT_TESTS_UBSAN 1
113bd8f1dc3Sbluhm # else
114bd8f1dc3Sbluhm # define EXPAT_TESTS_UBSAN 0
115bd8f1dc3Sbluhm # endif
116bd8f1dc3Sbluhm #else
117bd8f1dc3Sbluhm # define EXPAT_TESTS_UBSAN 0
118bd8f1dc3Sbluhm #endif
119bd8f1dc3Sbluhm
120bd8f1dc3Sbluhm /* Test that XML_ErrorString rejects out-of-range codes */
START_TEST(test_misc_error_string)121bd8f1dc3Sbluhm START_TEST(test_misc_error_string) {
122bd8f1dc3Sbluhm #if ! EXPAT_TESTS_UBSAN // because this would trigger UBSan
123bd8f1dc3Sbluhm union {
124bd8f1dc3Sbluhm enum XML_Error xml_error;
125bd8f1dc3Sbluhm int integer;
126bd8f1dc3Sbluhm } trickery;
127bd8f1dc3Sbluhm
128bd8f1dc3Sbluhm assert_true(sizeof(enum XML_Error) == sizeof(int)); // self-test
129bd8f1dc3Sbluhm
130bd8f1dc3Sbluhm trickery.integer = -1;
131bd8f1dc3Sbluhm if (XML_ErrorString(trickery.xml_error) != NULL)
132bd8f1dc3Sbluhm fail("Negative error code not rejected");
133bd8f1dc3Sbluhm
134bd8f1dc3Sbluhm trickery.integer = 100;
135bd8f1dc3Sbluhm if (XML_ErrorString(trickery.xml_error) != NULL)
136bd8f1dc3Sbluhm fail("Large error code not rejected");
137bd8f1dc3Sbluhm #endif
138bd8f1dc3Sbluhm }
139bd8f1dc3Sbluhm END_TEST
140bd8f1dc3Sbluhm
141bd8f1dc3Sbluhm /* Test the version information is consistent */
142bd8f1dc3Sbluhm
143bd8f1dc3Sbluhm /* Since we are working in XML_LChars (potentially 16-bits), we
144bd8f1dc3Sbluhm * can't use the standard C library functions for character
145bd8f1dc3Sbluhm * manipulation and have to roll our own.
146bd8f1dc3Sbluhm */
147bd8f1dc3Sbluhm static int
parse_version(const XML_LChar * version_text,XML_Expat_Version * version_struct)148bd8f1dc3Sbluhm parse_version(const XML_LChar *version_text,
149bd8f1dc3Sbluhm XML_Expat_Version *version_struct) {
150bd8f1dc3Sbluhm if (! version_text)
151bd8f1dc3Sbluhm return XML_FALSE;
152bd8f1dc3Sbluhm
153bd8f1dc3Sbluhm while (*version_text != 0x00) {
154bd8f1dc3Sbluhm if (*version_text >= ASCII_0 && *version_text <= ASCII_9)
155bd8f1dc3Sbluhm break;
156bd8f1dc3Sbluhm version_text++;
157bd8f1dc3Sbluhm }
158bd8f1dc3Sbluhm if (*version_text == 0x00)
159bd8f1dc3Sbluhm return XML_FALSE;
160bd8f1dc3Sbluhm
161bd8f1dc3Sbluhm /* version_struct->major = strtoul(version_text, 10, &version_text) */
162bd8f1dc3Sbluhm version_struct->major = 0;
163bd8f1dc3Sbluhm while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
164bd8f1dc3Sbluhm version_struct->major
165bd8f1dc3Sbluhm = 10 * version_struct->major + (*version_text++ - ASCII_0);
166bd8f1dc3Sbluhm }
167bd8f1dc3Sbluhm if (*version_text++ != ASCII_PERIOD)
168bd8f1dc3Sbluhm return XML_FALSE;
169bd8f1dc3Sbluhm
170bd8f1dc3Sbluhm /* Now for the minor version number */
171bd8f1dc3Sbluhm version_struct->minor = 0;
172bd8f1dc3Sbluhm while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
173bd8f1dc3Sbluhm version_struct->minor
174bd8f1dc3Sbluhm = 10 * version_struct->minor + (*version_text++ - ASCII_0);
175bd8f1dc3Sbluhm }
176bd8f1dc3Sbluhm if (*version_text++ != ASCII_PERIOD)
177bd8f1dc3Sbluhm return XML_FALSE;
178bd8f1dc3Sbluhm
179bd8f1dc3Sbluhm /* Finally the micro version number */
180bd8f1dc3Sbluhm version_struct->micro = 0;
181bd8f1dc3Sbluhm while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
182bd8f1dc3Sbluhm version_struct->micro
183bd8f1dc3Sbluhm = 10 * version_struct->micro + (*version_text++ - ASCII_0);
184bd8f1dc3Sbluhm }
185bd8f1dc3Sbluhm if (*version_text != 0x00)
186bd8f1dc3Sbluhm return XML_FALSE;
187bd8f1dc3Sbluhm return XML_TRUE;
188bd8f1dc3Sbluhm }
189bd8f1dc3Sbluhm
190bd8f1dc3Sbluhm static int
versions_equal(const XML_Expat_Version * first,const XML_Expat_Version * second)191bd8f1dc3Sbluhm versions_equal(const XML_Expat_Version *first,
192bd8f1dc3Sbluhm const XML_Expat_Version *second) {
193bd8f1dc3Sbluhm return (first->major == second->major && first->minor == second->minor
194bd8f1dc3Sbluhm && first->micro == second->micro);
195bd8f1dc3Sbluhm }
196bd8f1dc3Sbluhm
START_TEST(test_misc_version)197bd8f1dc3Sbluhm START_TEST(test_misc_version) {
198bd8f1dc3Sbluhm XML_Expat_Version read_version = XML_ExpatVersionInfo();
199bd8f1dc3Sbluhm /* Silence compiler warning with the following assignment */
200bd8f1dc3Sbluhm XML_Expat_Version parsed_version = {0, 0, 0};
201bd8f1dc3Sbluhm const XML_LChar *version_text = XML_ExpatVersion();
202bd8f1dc3Sbluhm
203bd8f1dc3Sbluhm if (version_text == NULL)
204bd8f1dc3Sbluhm fail("Could not obtain version text");
205bd8f1dc3Sbluhm assert(version_text != NULL);
206bd8f1dc3Sbluhm if (! parse_version(version_text, &parsed_version))
207bd8f1dc3Sbluhm fail("Unable to parse version text");
208bd8f1dc3Sbluhm if (! versions_equal(&read_version, &parsed_version))
209bd8f1dc3Sbluhm fail("Version mismatch");
210bd8f1dc3Sbluhm
211*c033f770Sbluhm if (xcstrcmp(version_text, XCS("expat_2.6.2"))) /* needs bump on releases */
212bd8f1dc3Sbluhm fail("XML_*_VERSION in expat.h out of sync?\n");
213bd8f1dc3Sbluhm }
214bd8f1dc3Sbluhm END_TEST
215bd8f1dc3Sbluhm
216bd8f1dc3Sbluhm /* Test feature information */
START_TEST(test_misc_features)217bd8f1dc3Sbluhm START_TEST(test_misc_features) {
218bd8f1dc3Sbluhm const XML_Feature *features = XML_GetFeatureList();
219bd8f1dc3Sbluhm
220bd8f1dc3Sbluhm /* Prevent problems with double-freeing parsers */
221bd8f1dc3Sbluhm g_parser = NULL;
222bd8f1dc3Sbluhm if (features == NULL) {
223bd8f1dc3Sbluhm fail("Failed to get feature information");
224bd8f1dc3Sbluhm } else {
225bd8f1dc3Sbluhm /* Loop through the features checking what we can */
226bd8f1dc3Sbluhm while (features->feature != XML_FEATURE_END) {
227bd8f1dc3Sbluhm switch (features->feature) {
228bd8f1dc3Sbluhm case XML_FEATURE_SIZEOF_XML_CHAR:
229bd8f1dc3Sbluhm if (features->value != sizeof(XML_Char))
230bd8f1dc3Sbluhm fail("Incorrect size of XML_Char");
231bd8f1dc3Sbluhm break;
232bd8f1dc3Sbluhm case XML_FEATURE_SIZEOF_XML_LCHAR:
233bd8f1dc3Sbluhm if (features->value != sizeof(XML_LChar))
234bd8f1dc3Sbluhm fail("Incorrect size of XML_LChar");
235bd8f1dc3Sbluhm break;
236bd8f1dc3Sbluhm default:
237bd8f1dc3Sbluhm break;
238bd8f1dc3Sbluhm }
239bd8f1dc3Sbluhm features++;
240bd8f1dc3Sbluhm }
241bd8f1dc3Sbluhm }
242bd8f1dc3Sbluhm }
243bd8f1dc3Sbluhm END_TEST
244bd8f1dc3Sbluhm
245bd8f1dc3Sbluhm /* Regression test for GitHub Issue #17: memory leak parsing attribute
246bd8f1dc3Sbluhm * values with mixed bound and unbound namespaces.
247bd8f1dc3Sbluhm */
START_TEST(test_misc_attribute_leak)248bd8f1dc3Sbluhm START_TEST(test_misc_attribute_leak) {
249bd8f1dc3Sbluhm const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
250bd8f1dc3Sbluhm XML_Memory_Handling_Suite memsuite
251bd8f1dc3Sbluhm = {tracking_malloc, tracking_realloc, tracking_free};
252bd8f1dc3Sbluhm
253bd8f1dc3Sbluhm g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
254bd8f1dc3Sbluhm expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
255bd8f1dc3Sbluhm XML_ParserFree(g_parser);
256bd8f1dc3Sbluhm /* Prevent the teardown trying to double free */
257bd8f1dc3Sbluhm g_parser = NULL;
258bd8f1dc3Sbluhm
259bd8f1dc3Sbluhm if (! tracking_report())
260bd8f1dc3Sbluhm fail("Memory leak found");
261bd8f1dc3Sbluhm }
262bd8f1dc3Sbluhm END_TEST
263bd8f1dc3Sbluhm
264bd8f1dc3Sbluhm /* Test parser created for UTF-16LE is successful */
START_TEST(test_misc_utf16le)265bd8f1dc3Sbluhm START_TEST(test_misc_utf16le) {
266bd8f1dc3Sbluhm const char text[] =
267bd8f1dc3Sbluhm /* <?xml version='1.0'?><q>Hi</q> */
268bd8f1dc3Sbluhm "<\0?\0x\0m\0l\0 \0"
269bd8f1dc3Sbluhm "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
270bd8f1dc3Sbluhm "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
271bd8f1dc3Sbluhm const XML_Char *expected = XCS("Hi");
272bd8f1dc3Sbluhm CharData storage;
273bd8f1dc3Sbluhm
274bd8f1dc3Sbluhm g_parser = XML_ParserCreate(XCS("UTF-16LE"));
275bd8f1dc3Sbluhm if (g_parser == NULL)
276bd8f1dc3Sbluhm fail("Parser not created");
277bd8f1dc3Sbluhm
278bd8f1dc3Sbluhm CharData_Init(&storage);
279bd8f1dc3Sbluhm XML_SetUserData(g_parser, &storage);
280bd8f1dc3Sbluhm XML_SetCharacterDataHandler(g_parser, accumulate_characters);
281bd8f1dc3Sbluhm if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
282bd8f1dc3Sbluhm == XML_STATUS_ERROR)
283bd8f1dc3Sbluhm xml_failure(g_parser);
284bd8f1dc3Sbluhm CharData_CheckXMLChars(&storage, expected);
285bd8f1dc3Sbluhm }
286bd8f1dc3Sbluhm END_TEST
287bd8f1dc3Sbluhm
START_TEST(test_misc_stop_during_end_handler_issue_240_1)288bd8f1dc3Sbluhm START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
289bd8f1dc3Sbluhm XML_Parser parser;
290bd8f1dc3Sbluhm DataIssue240 *mydata;
291bd8f1dc3Sbluhm enum XML_Status result;
292bd8f1dc3Sbluhm const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
293bd8f1dc3Sbluhm
294bd8f1dc3Sbluhm parser = XML_ParserCreate(NULL);
295bd8f1dc3Sbluhm XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
296bd8f1dc3Sbluhm mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
297bd8f1dc3Sbluhm mydata->parser = parser;
298bd8f1dc3Sbluhm mydata->deep = 0;
299bd8f1dc3Sbluhm XML_SetUserData(parser, mydata);
300bd8f1dc3Sbluhm
301bd8f1dc3Sbluhm result = _XML_Parse_SINGLE_BYTES(parser, doc1, (int)strlen(doc1), 1);
302bd8f1dc3Sbluhm XML_ParserFree(parser);
303bd8f1dc3Sbluhm free(mydata);
304bd8f1dc3Sbluhm if (result != XML_STATUS_ERROR)
305bd8f1dc3Sbluhm fail("Stopping the parser did not work as expected");
306bd8f1dc3Sbluhm }
307bd8f1dc3Sbluhm END_TEST
308bd8f1dc3Sbluhm
START_TEST(test_misc_stop_during_end_handler_issue_240_2)309bd8f1dc3Sbluhm START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
310bd8f1dc3Sbluhm XML_Parser parser;
311bd8f1dc3Sbluhm DataIssue240 *mydata;
312bd8f1dc3Sbluhm enum XML_Status result;
313bd8f1dc3Sbluhm const char *const doc2 = "<doc><elem/></doc>";
314bd8f1dc3Sbluhm
315bd8f1dc3Sbluhm parser = XML_ParserCreate(NULL);
316bd8f1dc3Sbluhm XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
317bd8f1dc3Sbluhm mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
318bd8f1dc3Sbluhm mydata->parser = parser;
319bd8f1dc3Sbluhm mydata->deep = 0;
320bd8f1dc3Sbluhm XML_SetUserData(parser, mydata);
321bd8f1dc3Sbluhm
322bd8f1dc3Sbluhm result = _XML_Parse_SINGLE_BYTES(parser, doc2, (int)strlen(doc2), 1);
323bd8f1dc3Sbluhm XML_ParserFree(parser);
324bd8f1dc3Sbluhm free(mydata);
325bd8f1dc3Sbluhm if (result != XML_STATUS_ERROR)
326bd8f1dc3Sbluhm fail("Stopping the parser did not work as expected");
327bd8f1dc3Sbluhm }
328bd8f1dc3Sbluhm END_TEST
329bd8f1dc3Sbluhm
START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317)330bd8f1dc3Sbluhm START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
331bd8f1dc3Sbluhm const char *const inputOne = "<!DOCTYPE d [\n"
332bd8f1dc3Sbluhm "<!ENTITY % e ']><d/>'>\n"
333bd8f1dc3Sbluhm "\n"
334bd8f1dc3Sbluhm "%e;";
335bd8f1dc3Sbluhm const char *const inputTwo = "<!DOCTYPE d [\n"
336bd8f1dc3Sbluhm "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
337bd8f1dc3Sbluhm "\n"
338bd8f1dc3Sbluhm "%e2;";
339bd8f1dc3Sbluhm const char *const inputThree = "<!DOCTYPE d [\n"
340bd8f1dc3Sbluhm "<!ENTITY % e ']><d'>\n"
341bd8f1dc3Sbluhm "\n"
342bd8f1dc3Sbluhm "%e;";
343bd8f1dc3Sbluhm const char *const inputIssue317 = "<!DOCTYPE doc [\n"
344bd8f1dc3Sbluhm "<!ENTITY % foo ']>\n"
345bd8f1dc3Sbluhm "<doc>Hell<oc (#PCDATA)*>'>\n"
346bd8f1dc3Sbluhm "%foo;\n"
347bd8f1dc3Sbluhm "]>\n"
348bd8f1dc3Sbluhm "<doc>Hello, world</dVc>";
349bd8f1dc3Sbluhm
350bd8f1dc3Sbluhm const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
351bd8f1dc3Sbluhm size_t inputIndex = 0;
352bd8f1dc3Sbluhm
353bd8f1dc3Sbluhm for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
354bd8f1dc3Sbluhm set_subtest("%s", inputs[inputIndex]);
355bd8f1dc3Sbluhm XML_Parser parser;
356bd8f1dc3Sbluhm enum XML_Status parseResult;
357bd8f1dc3Sbluhm int setParamEntityResult;
358bd8f1dc3Sbluhm XML_Size lineNumber;
359bd8f1dc3Sbluhm XML_Size columnNumber;
360bd8f1dc3Sbluhm const char *const input = inputs[inputIndex];
361bd8f1dc3Sbluhm
362bd8f1dc3Sbluhm parser = XML_ParserCreate(NULL);
363bd8f1dc3Sbluhm setParamEntityResult
364bd8f1dc3Sbluhm = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
365bd8f1dc3Sbluhm if (setParamEntityResult != 1)
366bd8f1dc3Sbluhm fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
367bd8f1dc3Sbluhm
368bd8f1dc3Sbluhm parseResult = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0);
369bd8f1dc3Sbluhm if (parseResult != XML_STATUS_ERROR) {
370bd8f1dc3Sbluhm parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1);
371bd8f1dc3Sbluhm if (parseResult != XML_STATUS_ERROR) {
372bd8f1dc3Sbluhm fail("Parsing was expected to fail but succeeded.");
373bd8f1dc3Sbluhm }
374bd8f1dc3Sbluhm }
375bd8f1dc3Sbluhm
376bd8f1dc3Sbluhm if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
377bd8f1dc3Sbluhm fail("Error code does not match XML_ERROR_INVALID_TOKEN");
378bd8f1dc3Sbluhm
379bd8f1dc3Sbluhm lineNumber = XML_GetCurrentLineNumber(parser);
380bd8f1dc3Sbluhm if (lineNumber != 4)
381bd8f1dc3Sbluhm fail("XML_GetCurrentLineNumber does not work as expected.");
382bd8f1dc3Sbluhm
383bd8f1dc3Sbluhm columnNumber = XML_GetCurrentColumnNumber(parser);
384bd8f1dc3Sbluhm if (columnNumber != 0)
385bd8f1dc3Sbluhm fail("XML_GetCurrentColumnNumber does not work as expected.");
386bd8f1dc3Sbluhm
387bd8f1dc3Sbluhm XML_ParserFree(parser);
388bd8f1dc3Sbluhm }
389bd8f1dc3Sbluhm }
390bd8f1dc3Sbluhm END_TEST
391bd8f1dc3Sbluhm
START_TEST(test_misc_tag_mismatch_reset_leak)392bd8f1dc3Sbluhm START_TEST(test_misc_tag_mismatch_reset_leak) {
393bd8f1dc3Sbluhm #ifdef XML_NS
394bd8f1dc3Sbluhm const char *const text = "<open xmlns='https://namespace1.test'></close>";
395bd8f1dc3Sbluhm XML_Parser parser = XML_ParserCreateNS(NULL, XCS('\n'));
396bd8f1dc3Sbluhm
397bd8f1dc3Sbluhm if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
398bd8f1dc3Sbluhm != XML_STATUS_ERROR)
399bd8f1dc3Sbluhm fail("Call to parse was expected to fail");
400bd8f1dc3Sbluhm if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH)
401bd8f1dc3Sbluhm fail("Call to parse was expected to fail from a closing tag mismatch");
402bd8f1dc3Sbluhm
403bd8f1dc3Sbluhm XML_ParserReset(parser, NULL);
404bd8f1dc3Sbluhm
405bd8f1dc3Sbluhm if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
406bd8f1dc3Sbluhm != XML_STATUS_ERROR)
407bd8f1dc3Sbluhm fail("Call to parse was expected to fail");
408bd8f1dc3Sbluhm if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH)
409bd8f1dc3Sbluhm fail("Call to parse was expected to fail from a closing tag mismatch");
410bd8f1dc3Sbluhm
411bd8f1dc3Sbluhm XML_ParserFree(parser);
412bd8f1dc3Sbluhm #endif
413bd8f1dc3Sbluhm }
414bd8f1dc3Sbluhm END_TEST
415bd8f1dc3Sbluhm
START_TEST(test_misc_create_external_entity_parser_with_null_context)416bd8f1dc3Sbluhm START_TEST(test_misc_create_external_entity_parser_with_null_context) {
417bd8f1dc3Sbluhm // With XML_DTD undefined, the only supported case of external entities
418bd8f1dc3Sbluhm // is pattern "<!ENTITY entity123 SYSTEM 'filename123'>". A NULL context
419bd8f1dc3Sbluhm // was causing a segfault through a null pointer dereference in function
420bd8f1dc3Sbluhm // setContext, previously.
421bd8f1dc3Sbluhm XML_Parser parser = XML_ParserCreate(NULL);
422bd8f1dc3Sbluhm XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
423bd8f1dc3Sbluhm #ifdef XML_DTD
424bd8f1dc3Sbluhm assert_true(ext_parser != NULL);
425bd8f1dc3Sbluhm XML_ParserFree(ext_parser);
426bd8f1dc3Sbluhm #else
427bd8f1dc3Sbluhm assert_true(ext_parser == NULL);
428bd8f1dc3Sbluhm #endif /* XML_DTD */
429bd8f1dc3Sbluhm XML_ParserFree(parser);
430bd8f1dc3Sbluhm }
431bd8f1dc3Sbluhm END_TEST
432bd8f1dc3Sbluhm
START_TEST(test_misc_general_entities_support)433bd8f1dc3Sbluhm START_TEST(test_misc_general_entities_support) {
434bd8f1dc3Sbluhm const char *const doc
435bd8f1dc3Sbluhm = "<!DOCTYPE r [\n"
436bd8f1dc3Sbluhm "<!ENTITY e1 'v1'>\n"
437bd8f1dc3Sbluhm "<!ENTITY e2 SYSTEM 'v2'>\n"
438bd8f1dc3Sbluhm "]>\n"
439bd8f1dc3Sbluhm "<r a1='[&e1;]'>[&e1;][&e2;][&'><"]</r>";
440bd8f1dc3Sbluhm
441bd8f1dc3Sbluhm CharData storage;
442bd8f1dc3Sbluhm CharData_Init(&storage);
443bd8f1dc3Sbluhm
444bd8f1dc3Sbluhm XML_Parser parser = XML_ParserCreate(NULL);
445bd8f1dc3Sbluhm XML_SetUserData(parser, &storage);
446bd8f1dc3Sbluhm XML_SetStartElementHandler(parser, accumulate_start_element);
447bd8f1dc3Sbluhm XML_SetExternalEntityRefHandler(parser,
448bd8f1dc3Sbluhm external_entity_failer__if_not_xml_ge);
449bd8f1dc3Sbluhm XML_SetEntityDeclHandler(parser, accumulate_entity_decl);
450bd8f1dc3Sbluhm XML_SetCharacterDataHandler(parser, accumulate_char_data);
451bd8f1dc3Sbluhm
452bd8f1dc3Sbluhm if (_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
453bd8f1dc3Sbluhm != XML_STATUS_OK) {
454bd8f1dc3Sbluhm xml_failure(parser);
455bd8f1dc3Sbluhm }
456bd8f1dc3Sbluhm
457bd8f1dc3Sbluhm XML_ParserFree(parser);
458bd8f1dc3Sbluhm
459bd8f1dc3Sbluhm CharData_CheckXMLChars(&storage,
460bd8f1dc3Sbluhm /* clang-format off */
461bd8f1dc3Sbluhm #if XML_GE == 1
462bd8f1dc3Sbluhm XCS("e1=v1\n")
463bd8f1dc3Sbluhm XCS("e2=(null)\n")
464bd8f1dc3Sbluhm XCS("(r(a1=[v1]))\n")
465bd8f1dc3Sbluhm XCS("[v1][][&'><\"]")
466bd8f1dc3Sbluhm #else
467bd8f1dc3Sbluhm XCS("e1=&e1;\n")
468bd8f1dc3Sbluhm XCS("e2=(null)\n")
469bd8f1dc3Sbluhm XCS("(r(a1=[&e1;]))\n")
470bd8f1dc3Sbluhm XCS("[&e1;][&e2;][&'><\"]")
471bd8f1dc3Sbluhm #endif
472bd8f1dc3Sbluhm );
473bd8f1dc3Sbluhm /* clang-format on */
474bd8f1dc3Sbluhm }
475bd8f1dc3Sbluhm END_TEST
476bd8f1dc3Sbluhm
477bd8f1dc3Sbluhm static void XMLCALL
resumable_stopping_character_handler(void * userData,const XML_Char * s,int len)478bd8f1dc3Sbluhm resumable_stopping_character_handler(void *userData, const XML_Char *s,
479bd8f1dc3Sbluhm int len) {
480bd8f1dc3Sbluhm UNUSED_P(s);
481bd8f1dc3Sbluhm UNUSED_P(len);
482bd8f1dc3Sbluhm XML_Parser parser = (XML_Parser)userData;
483bd8f1dc3Sbluhm XML_StopParser(parser, XML_TRUE);
484bd8f1dc3Sbluhm }
485bd8f1dc3Sbluhm
486bd8f1dc3Sbluhm // NOTE: This test needs active LeakSanitizer to be of actual use
START_TEST(test_misc_char_handler_stop_without_leak)487bd8f1dc3Sbluhm START_TEST(test_misc_char_handler_stop_without_leak) {
488bd8f1dc3Sbluhm const char *const data
489bd8f1dc3Sbluhm = "<!DOCTYPE t1[<!ENTITY e1 'angle<'><!ENTITY e2 '&e1;'>]><t1>&e2;";
490bd8f1dc3Sbluhm XML_Parser parser = XML_ParserCreate(NULL);
491bd8f1dc3Sbluhm assert_true(parser != NULL);
492bd8f1dc3Sbluhm XML_SetUserData(parser, parser);
493bd8f1dc3Sbluhm XML_SetCharacterDataHandler(parser, resumable_stopping_character_handler);
494bd8f1dc3Sbluhm _XML_Parse_SINGLE_BYTES(parser, data, (int)strlen(data), XML_FALSE);
495bd8f1dc3Sbluhm XML_ParserFree(parser);
496bd8f1dc3Sbluhm }
497bd8f1dc3Sbluhm END_TEST
498bd8f1dc3Sbluhm
499bd8f1dc3Sbluhm void
make_miscellaneous_test_case(Suite * s)500bd8f1dc3Sbluhm make_miscellaneous_test_case(Suite *s) {
501bd8f1dc3Sbluhm TCase *tc_misc = tcase_create("miscellaneous tests");
502bd8f1dc3Sbluhm
503bd8f1dc3Sbluhm suite_add_tcase(s, tc_misc);
504bd8f1dc3Sbluhm tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
505bd8f1dc3Sbluhm
506bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_alloc_create_parser);
507bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding);
508bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_null_parser);
509bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_error_string);
510bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_version);
511bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_features);
512bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_attribute_leak);
513bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_utf16le);
514bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1);
515bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2);
516bd8f1dc3Sbluhm tcase_add_test__ifdef_xml_dtd(
517bd8f1dc3Sbluhm tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317);
518bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_tag_mismatch_reset_leak);
519bd8f1dc3Sbluhm tcase_add_test(tc_misc,
520bd8f1dc3Sbluhm test_misc_create_external_entity_parser_with_null_context);
521bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_general_entities_support);
522bd8f1dc3Sbluhm tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
523bd8f1dc3Sbluhm }
524