14543ef51SXin LI /* Tests in the "miscellaneous" test case for the Expat test suite 24543ef51SXin LI __ __ _ 34543ef51SXin LI ___\ \/ /_ __ __ _| |_ 44543ef51SXin LI / _ \\ /| '_ \ / _` | __| 54543ef51SXin LI | __// \| |_) | (_| | |_ 64543ef51SXin LI \___/_/\_\ .__/ \__,_|\__| 74543ef51SXin LI |_| XML parser 84543ef51SXin LI 94543ef51SXin LI Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net> 104543ef51SXin LI Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net> 114543ef51SXin LI Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> 124543ef51SXin LI Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net> 134543ef51SXin LI Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org> 144543ef51SXin LI Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk> 154543ef51SXin LI Copyright (c) 2017 Joe Orton <jorton@redhat.com> 164543ef51SXin LI Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com> 174543ef51SXin LI Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it> 184543ef51SXin LI Copyright (c) 2019 David Loffredo <loffredo@steptools.com> 194543ef51SXin LI Copyright (c) 2020 Tim Gates <tim.gates@iress.com> 204543ef51SXin LI Copyright (c) 2021 Donghee Na <donghee.na@python.org> 214543ef51SXin LI Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com> 224543ef51SXin LI Licensed under the MIT license: 234543ef51SXin LI 244543ef51SXin LI Permission is hereby granted, free of charge, to any person obtaining 254543ef51SXin LI a copy of this software and associated documentation files (the 264543ef51SXin LI "Software"), to deal in the Software without restriction, including 274543ef51SXin LI without limitation the rights to use, copy, modify, merge, publish, 284543ef51SXin LI distribute, sublicense, and/or sell copies of the Software, and to permit 294543ef51SXin LI persons to whom the Software is furnished to do so, subject to the 304543ef51SXin LI following conditions: 314543ef51SXin LI 324543ef51SXin LI The above copyright notice and this permission notice shall be included 334543ef51SXin LI in all copies or substantial portions of the Software. 344543ef51SXin LI 354543ef51SXin LI THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 364543ef51SXin LI EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 374543ef51SXin LI MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 384543ef51SXin LI NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 394543ef51SXin LI DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 404543ef51SXin LI OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 414543ef51SXin LI USE OR OTHER DEALINGS IN THE SOFTWARE. 424543ef51SXin LI */ 434543ef51SXin LI 444543ef51SXin LI #if defined(NDEBUG) 454543ef51SXin LI # undef NDEBUG /* because test suite relies on assert(...) at the moment */ 464543ef51SXin LI #endif 474543ef51SXin LI 484543ef51SXin LI #include <assert.h> 494543ef51SXin LI #include <string.h> 504543ef51SXin LI 514543ef51SXin LI #include "expat_config.h" 524543ef51SXin LI 534543ef51SXin LI #include "expat.h" 544543ef51SXin LI #include "internal.h" 554543ef51SXin LI #include "minicheck.h" 564543ef51SXin LI #include "memcheck.h" 574543ef51SXin LI #include "common.h" 584543ef51SXin LI #include "ascii.h" /* for ASCII_xxx */ 594543ef51SXin LI #include "handlers.h" 604543ef51SXin LI #include "misc_tests.h" 614543ef51SXin LI 624543ef51SXin LI /* Test that a failure to allocate the parser structure fails gracefully */ 634543ef51SXin LI START_TEST(test_misc_alloc_create_parser) { 644543ef51SXin LI XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free}; 654543ef51SXin LI unsigned int i; 664543ef51SXin LI const unsigned int max_alloc_count = 10; 674543ef51SXin LI 684543ef51SXin LI /* Something this simple shouldn't need more than 10 allocations */ 694543ef51SXin LI for (i = 0; i < max_alloc_count; i++) { 704543ef51SXin LI g_allocation_count = i; 714543ef51SXin LI g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL); 724543ef51SXin LI if (g_parser != NULL) 734543ef51SXin LI break; 744543ef51SXin LI } 754543ef51SXin LI if (i == 0) 764543ef51SXin LI fail("Parser unexpectedly ignored failing allocator"); 774543ef51SXin LI else if (i == max_alloc_count) 784543ef51SXin LI fail("Parser not created with max allocation count"); 794543ef51SXin LI } 804543ef51SXin LI END_TEST 814543ef51SXin LI 824543ef51SXin LI /* Test memory allocation failures for a parser with an encoding */ 834543ef51SXin LI START_TEST(test_misc_alloc_create_parser_with_encoding) { 844543ef51SXin LI XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free}; 854543ef51SXin LI unsigned int i; 864543ef51SXin LI const unsigned int max_alloc_count = 10; 874543ef51SXin LI 884543ef51SXin LI /* Try several levels of allocation */ 894543ef51SXin LI for (i = 0; i < max_alloc_count; i++) { 904543ef51SXin LI g_allocation_count = i; 914543ef51SXin LI g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL); 924543ef51SXin LI if (g_parser != NULL) 934543ef51SXin LI break; 944543ef51SXin LI } 954543ef51SXin LI if (i == 0) 964543ef51SXin LI fail("Parser ignored failing allocator"); 974543ef51SXin LI else if (i == max_alloc_count) 984543ef51SXin LI fail("Parser not created with max allocation count"); 994543ef51SXin LI } 1004543ef51SXin LI END_TEST 1014543ef51SXin LI 1024543ef51SXin LI /* Test that freeing a NULL parser doesn't cause an explosion. 1034543ef51SXin LI * (Not actually tested anywhere else) 1044543ef51SXin LI */ 1054543ef51SXin LI START_TEST(test_misc_null_parser) { 1064543ef51SXin LI XML_ParserFree(NULL); 1074543ef51SXin LI } 1084543ef51SXin LI END_TEST 1094543ef51SXin LI 1104543ef51SXin LI #if defined(__has_feature) 1114543ef51SXin LI # if __has_feature(undefined_behavior_sanitizer) 1124543ef51SXin LI # define EXPAT_TESTS_UBSAN 1 1134543ef51SXin LI # else 1144543ef51SXin LI # define EXPAT_TESTS_UBSAN 0 1154543ef51SXin LI # endif 1164543ef51SXin LI #else 1174543ef51SXin LI # define EXPAT_TESTS_UBSAN 0 1184543ef51SXin LI #endif 1194543ef51SXin LI 1204543ef51SXin LI /* Test that XML_ErrorString rejects out-of-range codes */ 1214543ef51SXin LI START_TEST(test_misc_error_string) { 1224543ef51SXin LI #if ! EXPAT_TESTS_UBSAN // because this would trigger UBSan 1234543ef51SXin LI union { 1244543ef51SXin LI enum XML_Error xml_error; 1254543ef51SXin LI int integer; 1264543ef51SXin LI } trickery; 1274543ef51SXin LI 1284543ef51SXin LI assert_true(sizeof(enum XML_Error) == sizeof(int)); // self-test 1294543ef51SXin LI 1304543ef51SXin LI trickery.integer = -1; 1314543ef51SXin LI if (XML_ErrorString(trickery.xml_error) != NULL) 1324543ef51SXin LI fail("Negative error code not rejected"); 1334543ef51SXin LI 1344543ef51SXin LI trickery.integer = 100; 1354543ef51SXin LI if (XML_ErrorString(trickery.xml_error) != NULL) 1364543ef51SXin LI fail("Large error code not rejected"); 1374543ef51SXin LI #endif 1384543ef51SXin LI } 1394543ef51SXin LI END_TEST 1404543ef51SXin LI 1414543ef51SXin LI /* Test the version information is consistent */ 1424543ef51SXin LI 1434543ef51SXin LI /* Since we are working in XML_LChars (potentially 16-bits), we 1444543ef51SXin LI * can't use the standard C library functions for character 1454543ef51SXin LI * manipulation and have to roll our own. 1464543ef51SXin LI */ 1474543ef51SXin LI static int 1484543ef51SXin LI parse_version(const XML_LChar *version_text, 1494543ef51SXin LI XML_Expat_Version *version_struct) { 1504543ef51SXin LI if (! version_text) 1514543ef51SXin LI return XML_FALSE; 1524543ef51SXin LI 1534543ef51SXin LI while (*version_text != 0x00) { 1544543ef51SXin LI if (*version_text >= ASCII_0 && *version_text <= ASCII_9) 1554543ef51SXin LI break; 1564543ef51SXin LI version_text++; 1574543ef51SXin LI } 1584543ef51SXin LI if (*version_text == 0x00) 1594543ef51SXin LI return XML_FALSE; 1604543ef51SXin LI 1614543ef51SXin LI /* version_struct->major = strtoul(version_text, 10, &version_text) */ 1624543ef51SXin LI version_struct->major = 0; 1634543ef51SXin LI while (*version_text >= ASCII_0 && *version_text <= ASCII_9) { 1644543ef51SXin LI version_struct->major 1654543ef51SXin LI = 10 * version_struct->major + (*version_text++ - ASCII_0); 1664543ef51SXin LI } 1674543ef51SXin LI if (*version_text++ != ASCII_PERIOD) 1684543ef51SXin LI return XML_FALSE; 1694543ef51SXin LI 1704543ef51SXin LI /* Now for the minor version number */ 1714543ef51SXin LI version_struct->minor = 0; 1724543ef51SXin LI while (*version_text >= ASCII_0 && *version_text <= ASCII_9) { 1734543ef51SXin LI version_struct->minor 1744543ef51SXin LI = 10 * version_struct->minor + (*version_text++ - ASCII_0); 1754543ef51SXin LI } 1764543ef51SXin LI if (*version_text++ != ASCII_PERIOD) 1774543ef51SXin LI return XML_FALSE; 1784543ef51SXin LI 1794543ef51SXin LI /* Finally the micro version number */ 1804543ef51SXin LI version_struct->micro = 0; 1814543ef51SXin LI while (*version_text >= ASCII_0 && *version_text <= ASCII_9) { 1824543ef51SXin LI version_struct->micro 1834543ef51SXin LI = 10 * version_struct->micro + (*version_text++ - ASCII_0); 1844543ef51SXin LI } 1854543ef51SXin LI if (*version_text != 0x00) 1864543ef51SXin LI return XML_FALSE; 1874543ef51SXin LI return XML_TRUE; 1884543ef51SXin LI } 1894543ef51SXin LI 1904543ef51SXin LI static int 1914543ef51SXin LI versions_equal(const XML_Expat_Version *first, 1924543ef51SXin LI const XML_Expat_Version *second) { 1934543ef51SXin LI return (first->major == second->major && first->minor == second->minor 1944543ef51SXin LI && first->micro == second->micro); 1954543ef51SXin LI } 1964543ef51SXin LI 1974543ef51SXin LI START_TEST(test_misc_version) { 1984543ef51SXin LI XML_Expat_Version read_version = XML_ExpatVersionInfo(); 1994543ef51SXin LI /* Silence compiler warning with the following assignment */ 2004543ef51SXin LI XML_Expat_Version parsed_version = {0, 0, 0}; 2014543ef51SXin LI const XML_LChar *version_text = XML_ExpatVersion(); 2024543ef51SXin LI 2034543ef51SXin LI if (version_text == NULL) 2044543ef51SXin LI fail("Could not obtain version text"); 2054543ef51SXin LI assert(version_text != NULL); 2064543ef51SXin LI if (! parse_version(version_text, &parsed_version)) 2074543ef51SXin LI fail("Unable to parse version text"); 2084543ef51SXin LI if (! versions_equal(&read_version, &parsed_version)) 2094543ef51SXin LI fail("Version mismatch"); 2104543ef51SXin LI 211*908f215eSXin LI if (xcstrcmp(version_text, XCS("expat_2.6.4"))) /* needs bump on releases */ 2124543ef51SXin LI fail("XML_*_VERSION in expat.h out of sync?\n"); 2134543ef51SXin LI } 2144543ef51SXin LI END_TEST 2154543ef51SXin LI 2164543ef51SXin LI /* Test feature information */ 2174543ef51SXin LI START_TEST(test_misc_features) { 2184543ef51SXin LI const XML_Feature *features = XML_GetFeatureList(); 2194543ef51SXin LI 2204543ef51SXin LI /* Prevent problems with double-freeing parsers */ 2214543ef51SXin LI g_parser = NULL; 2224543ef51SXin LI if (features == NULL) { 2234543ef51SXin LI fail("Failed to get feature information"); 2244543ef51SXin LI } else { 2254543ef51SXin LI /* Loop through the features checking what we can */ 2264543ef51SXin LI while (features->feature != XML_FEATURE_END) { 2274543ef51SXin LI switch (features->feature) { 2284543ef51SXin LI case XML_FEATURE_SIZEOF_XML_CHAR: 2294543ef51SXin LI if (features->value != sizeof(XML_Char)) 2304543ef51SXin LI fail("Incorrect size of XML_Char"); 2314543ef51SXin LI break; 2324543ef51SXin LI case XML_FEATURE_SIZEOF_XML_LCHAR: 2334543ef51SXin LI if (features->value != sizeof(XML_LChar)) 2344543ef51SXin LI fail("Incorrect size of XML_LChar"); 2354543ef51SXin LI break; 2364543ef51SXin LI default: 2374543ef51SXin LI break; 2384543ef51SXin LI } 2394543ef51SXin LI features++; 2404543ef51SXin LI } 2414543ef51SXin LI } 2424543ef51SXin LI } 2434543ef51SXin LI END_TEST 2444543ef51SXin LI 2454543ef51SXin LI /* Regression test for GitHub Issue #17: memory leak parsing attribute 2464543ef51SXin LI * values with mixed bound and unbound namespaces. 2474543ef51SXin LI */ 2484543ef51SXin LI START_TEST(test_misc_attribute_leak) { 2494543ef51SXin LI const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>"; 2504543ef51SXin LI XML_Memory_Handling_Suite memsuite 2514543ef51SXin LI = {tracking_malloc, tracking_realloc, tracking_free}; 2524543ef51SXin LI 2534543ef51SXin LI g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n")); 2544543ef51SXin LI expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found"); 2554543ef51SXin LI XML_ParserFree(g_parser); 2564543ef51SXin LI /* Prevent the teardown trying to double free */ 2574543ef51SXin LI g_parser = NULL; 2584543ef51SXin LI 2594543ef51SXin LI if (! tracking_report()) 2604543ef51SXin LI fail("Memory leak found"); 2614543ef51SXin LI } 2624543ef51SXin LI END_TEST 2634543ef51SXin LI 2644543ef51SXin LI /* Test parser created for UTF-16LE is successful */ 2654543ef51SXin LI START_TEST(test_misc_utf16le) { 2664543ef51SXin LI const char text[] = 2674543ef51SXin LI /* <?xml version='1.0'?><q>Hi</q> */ 2684543ef51SXin LI "<\0?\0x\0m\0l\0 \0" 2694543ef51SXin LI "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0" 2704543ef51SXin LI "<\0q\0>\0H\0i\0<\0/\0q\0>\0"; 2714543ef51SXin LI const XML_Char *expected = XCS("Hi"); 2724543ef51SXin LI CharData storage; 2734543ef51SXin LI 2744543ef51SXin LI g_parser = XML_ParserCreate(XCS("UTF-16LE")); 2754543ef51SXin LI if (g_parser == NULL) 2764543ef51SXin LI fail("Parser not created"); 2774543ef51SXin LI 2784543ef51SXin LI CharData_Init(&storage); 2794543ef51SXin LI XML_SetUserData(g_parser, &storage); 2804543ef51SXin LI XML_SetCharacterDataHandler(g_parser, accumulate_characters); 2814543ef51SXin LI if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE) 2824543ef51SXin LI == XML_STATUS_ERROR) 2834543ef51SXin LI xml_failure(g_parser); 2844543ef51SXin LI CharData_CheckXMLChars(&storage, expected); 2854543ef51SXin LI } 2864543ef51SXin LI END_TEST 2874543ef51SXin LI 2884543ef51SXin LI START_TEST(test_misc_stop_during_end_handler_issue_240_1) { 2894543ef51SXin LI XML_Parser parser; 2904543ef51SXin LI DataIssue240 *mydata; 2914543ef51SXin LI enum XML_Status result; 2924543ef51SXin LI const char *const doc1 = "<doc><e1/><e><foo/></e></doc>"; 2934543ef51SXin LI 2944543ef51SXin LI parser = XML_ParserCreate(NULL); 2954543ef51SXin LI XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240); 2964543ef51SXin LI mydata = (DataIssue240 *)malloc(sizeof(DataIssue240)); 2974543ef51SXin LI mydata->parser = parser; 2984543ef51SXin LI mydata->deep = 0; 2994543ef51SXin LI XML_SetUserData(parser, mydata); 3004543ef51SXin LI 3014543ef51SXin LI result = _XML_Parse_SINGLE_BYTES(parser, doc1, (int)strlen(doc1), 1); 3024543ef51SXin LI XML_ParserFree(parser); 3034543ef51SXin LI free(mydata); 3044543ef51SXin LI if (result != XML_STATUS_ERROR) 3054543ef51SXin LI fail("Stopping the parser did not work as expected"); 3064543ef51SXin LI } 3074543ef51SXin LI END_TEST 3084543ef51SXin LI 3094543ef51SXin LI START_TEST(test_misc_stop_during_end_handler_issue_240_2) { 3104543ef51SXin LI XML_Parser parser; 3114543ef51SXin LI DataIssue240 *mydata; 3124543ef51SXin LI enum XML_Status result; 3134543ef51SXin LI const char *const doc2 = "<doc><elem/></doc>"; 3144543ef51SXin LI 3154543ef51SXin LI parser = XML_ParserCreate(NULL); 3164543ef51SXin LI XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240); 3174543ef51SXin LI mydata = (DataIssue240 *)malloc(sizeof(DataIssue240)); 3184543ef51SXin LI mydata->parser = parser; 3194543ef51SXin LI mydata->deep = 0; 3204543ef51SXin LI XML_SetUserData(parser, mydata); 3214543ef51SXin LI 3224543ef51SXin LI result = _XML_Parse_SINGLE_BYTES(parser, doc2, (int)strlen(doc2), 1); 3234543ef51SXin LI XML_ParserFree(parser); 3244543ef51SXin LI free(mydata); 3254543ef51SXin LI if (result != XML_STATUS_ERROR) 3264543ef51SXin LI fail("Stopping the parser did not work as expected"); 3274543ef51SXin LI } 3284543ef51SXin LI END_TEST 3294543ef51SXin LI 3304543ef51SXin LI START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) { 3314543ef51SXin LI const char *const inputOne = "<!DOCTYPE d [\n" 3324543ef51SXin LI "<!ENTITY % e ']><d/>'>\n" 3334543ef51SXin LI "\n" 3344543ef51SXin LI "%e;"; 335*908f215eSXin LI const char *const inputTwo 336*908f215eSXin LI = "<!DOCTYPE d [\n" 337*908f215eSXin LI "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '%e1;'>\n" 3384543ef51SXin LI "\n" 3394543ef51SXin LI "%e2;"; 3404543ef51SXin LI const char *const inputThree = "<!DOCTYPE d [\n" 3414543ef51SXin LI "<!ENTITY % e ']><d'>\n" 3424543ef51SXin LI "\n" 343*908f215eSXin LI "%e;/>"; 3444543ef51SXin LI const char *const inputIssue317 = "<!DOCTYPE doc [\n" 3454543ef51SXin LI "<!ENTITY % foo ']>\n" 3464543ef51SXin LI "<doc>Hell<oc (#PCDATA)*>'>\n" 3474543ef51SXin LI "%foo;\n" 3484543ef51SXin LI "]>\n" 3494543ef51SXin LI "<doc>Hello, world</dVc>"; 3504543ef51SXin LI 3514543ef51SXin LI const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317}; 3524543ef51SXin LI size_t inputIndex = 0; 3534543ef51SXin LI 3544543ef51SXin LI for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) { 3554543ef51SXin LI set_subtest("%s", inputs[inputIndex]); 3564543ef51SXin LI XML_Parser parser; 3574543ef51SXin LI enum XML_Status parseResult; 3584543ef51SXin LI int setParamEntityResult; 3594543ef51SXin LI XML_Size lineNumber; 3604543ef51SXin LI XML_Size columnNumber; 3614543ef51SXin LI const char *const input = inputs[inputIndex]; 3624543ef51SXin LI 3634543ef51SXin LI parser = XML_ParserCreate(NULL); 3644543ef51SXin LI setParamEntityResult 3654543ef51SXin LI = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); 3664543ef51SXin LI if (setParamEntityResult != 1) 3674543ef51SXin LI fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS."); 3684543ef51SXin LI 3694543ef51SXin LI parseResult = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0); 3704543ef51SXin LI if (parseResult != XML_STATUS_ERROR) { 3714543ef51SXin LI parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1); 3724543ef51SXin LI if (parseResult != XML_STATUS_ERROR) { 3734543ef51SXin LI fail("Parsing was expected to fail but succeeded."); 3744543ef51SXin LI } 3754543ef51SXin LI } 3764543ef51SXin LI 3774543ef51SXin LI if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) 3784543ef51SXin LI fail("Error code does not match XML_ERROR_INVALID_TOKEN"); 3794543ef51SXin LI 3804543ef51SXin LI lineNumber = XML_GetCurrentLineNumber(parser); 3814543ef51SXin LI if (lineNumber != 4) 3824543ef51SXin LI fail("XML_GetCurrentLineNumber does not work as expected."); 3834543ef51SXin LI 3844543ef51SXin LI columnNumber = XML_GetCurrentColumnNumber(parser); 3854543ef51SXin LI if (columnNumber != 0) 3864543ef51SXin LI fail("XML_GetCurrentColumnNumber does not work as expected."); 3874543ef51SXin LI 3884543ef51SXin LI XML_ParserFree(parser); 3894543ef51SXin LI } 3904543ef51SXin LI } 3914543ef51SXin LI END_TEST 3924543ef51SXin LI 3934543ef51SXin LI START_TEST(test_misc_tag_mismatch_reset_leak) { 3944543ef51SXin LI #ifdef XML_NS 3954543ef51SXin LI const char *const text = "<open xmlns='https://namespace1.test'></close>"; 3964543ef51SXin LI XML_Parser parser = XML_ParserCreateNS(NULL, XCS('\n')); 3974543ef51SXin LI 3984543ef51SXin LI if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 3994543ef51SXin LI != XML_STATUS_ERROR) 4004543ef51SXin LI fail("Call to parse was expected to fail"); 4014543ef51SXin LI if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH) 4024543ef51SXin LI fail("Call to parse was expected to fail from a closing tag mismatch"); 4034543ef51SXin LI 4044543ef51SXin LI XML_ParserReset(parser, NULL); 4054543ef51SXin LI 4064543ef51SXin LI if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) 4074543ef51SXin LI != XML_STATUS_ERROR) 4084543ef51SXin LI fail("Call to parse was expected to fail"); 4094543ef51SXin LI if (XML_GetErrorCode(parser) != XML_ERROR_TAG_MISMATCH) 4104543ef51SXin LI fail("Call to parse was expected to fail from a closing tag mismatch"); 4114543ef51SXin LI 4124543ef51SXin LI XML_ParserFree(parser); 4134543ef51SXin LI #endif 4144543ef51SXin LI } 4154543ef51SXin LI END_TEST 4164543ef51SXin LI 4174543ef51SXin LI START_TEST(test_misc_create_external_entity_parser_with_null_context) { 4184543ef51SXin LI // With XML_DTD undefined, the only supported case of external entities 4194543ef51SXin LI // is pattern "<!ENTITY entity123 SYSTEM 'filename123'>". A NULL context 4204543ef51SXin LI // was causing a segfault through a null pointer dereference in function 4214543ef51SXin LI // setContext, previously. 4224543ef51SXin LI XML_Parser parser = XML_ParserCreate(NULL); 4234543ef51SXin LI XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL); 4244543ef51SXin LI #ifdef XML_DTD 4254543ef51SXin LI assert_true(ext_parser != NULL); 4264543ef51SXin LI XML_ParserFree(ext_parser); 4274543ef51SXin LI #else 4284543ef51SXin LI assert_true(ext_parser == NULL); 4294543ef51SXin LI #endif /* XML_DTD */ 4304543ef51SXin LI XML_ParserFree(parser); 4314543ef51SXin LI } 4324543ef51SXin LI END_TEST 4334543ef51SXin LI 4344543ef51SXin LI START_TEST(test_misc_general_entities_support) { 4354543ef51SXin LI const char *const doc 4364543ef51SXin LI = "<!DOCTYPE r [\n" 4374543ef51SXin LI "<!ENTITY e1 'v1'>\n" 4384543ef51SXin LI "<!ENTITY e2 SYSTEM 'v2'>\n" 4394543ef51SXin LI "]>\n" 4404543ef51SXin LI "<r a1='[&e1;]'>[&e1;][&e2;][&'><"]</r>"; 4414543ef51SXin LI 4424543ef51SXin LI CharData storage; 4434543ef51SXin LI CharData_Init(&storage); 4444543ef51SXin LI 4454543ef51SXin LI XML_Parser parser = XML_ParserCreate(NULL); 4464543ef51SXin LI XML_SetUserData(parser, &storage); 4474543ef51SXin LI XML_SetStartElementHandler(parser, accumulate_start_element); 4484543ef51SXin LI XML_SetExternalEntityRefHandler(parser, 4494543ef51SXin LI external_entity_failer__if_not_xml_ge); 4504543ef51SXin LI XML_SetEntityDeclHandler(parser, accumulate_entity_decl); 451*908f215eSXin LI XML_SetCharacterDataHandler(parser, accumulate_characters); 4524543ef51SXin LI 4534543ef51SXin LI if (_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE) 4544543ef51SXin LI != XML_STATUS_OK) { 4554543ef51SXin LI xml_failure(parser); 4564543ef51SXin LI } 4574543ef51SXin LI 4584543ef51SXin LI XML_ParserFree(parser); 4594543ef51SXin LI 4604543ef51SXin LI CharData_CheckXMLChars(&storage, 4614543ef51SXin LI /* clang-format off */ 4624543ef51SXin LI #if XML_GE == 1 4634543ef51SXin LI XCS("e1=v1\n") 4644543ef51SXin LI XCS("e2=(null)\n") 4654543ef51SXin LI XCS("(r(a1=[v1]))\n") 4664543ef51SXin LI XCS("[v1][][&'><\"]") 4674543ef51SXin LI #else 4684543ef51SXin LI XCS("e1=&e1;\n") 4694543ef51SXin LI XCS("e2=(null)\n") 4704543ef51SXin LI XCS("(r(a1=[&e1;]))\n") 4714543ef51SXin LI XCS("[&e1;][&e2;][&'><\"]") 4724543ef51SXin LI #endif 4734543ef51SXin LI ); 4744543ef51SXin LI /* clang-format on */ 4754543ef51SXin LI } 4764543ef51SXin LI END_TEST 4774543ef51SXin LI 4784543ef51SXin LI static void XMLCALL 4794543ef51SXin LI resumable_stopping_character_handler(void *userData, const XML_Char *s, 4804543ef51SXin LI int len) { 4814543ef51SXin LI UNUSED_P(s); 4824543ef51SXin LI UNUSED_P(len); 4834543ef51SXin LI XML_Parser parser = (XML_Parser)userData; 4844543ef51SXin LI XML_StopParser(parser, XML_TRUE); 4854543ef51SXin LI } 4864543ef51SXin LI 4874543ef51SXin LI // NOTE: This test needs active LeakSanitizer to be of actual use 4884543ef51SXin LI START_TEST(test_misc_char_handler_stop_without_leak) { 4894543ef51SXin LI const char *const data 4904543ef51SXin LI = "<!DOCTYPE t1[<!ENTITY e1 'angle<'><!ENTITY e2 '&e1;'>]><t1>&e2;"; 4914543ef51SXin LI XML_Parser parser = XML_ParserCreate(NULL); 4924543ef51SXin LI assert_true(parser != NULL); 4934543ef51SXin LI XML_SetUserData(parser, parser); 4944543ef51SXin LI XML_SetCharacterDataHandler(parser, resumable_stopping_character_handler); 4954543ef51SXin LI _XML_Parse_SINGLE_BYTES(parser, data, (int)strlen(data), XML_FALSE); 4964543ef51SXin LI XML_ParserFree(parser); 4974543ef51SXin LI } 4984543ef51SXin LI END_TEST 4994543ef51SXin LI 500*908f215eSXin LI START_TEST(test_misc_resumeparser_not_crashing) { 501*908f215eSXin LI XML_Parser parser = XML_ParserCreate(NULL); 502*908f215eSXin LI XML_GetBuffer(parser, 1); 503*908f215eSXin LI XML_StopParser(parser, /*resumable=*/XML_TRUE); 504*908f215eSXin LI XML_ResumeParser(parser); // could crash here, previously 505*908f215eSXin LI XML_ParserFree(parser); 506*908f215eSXin LI } 507*908f215eSXin LI END_TEST 508*908f215eSXin LI 509*908f215eSXin LI START_TEST(test_misc_stopparser_rejects_unstarted_parser) { 510*908f215eSXin LI const XML_Bool cases[] = {XML_TRUE, XML_FALSE}; 511*908f215eSXin LI for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { 512*908f215eSXin LI const XML_Bool resumable = cases[i]; 513*908f215eSXin LI XML_Parser parser = XML_ParserCreate(NULL); 514*908f215eSXin LI assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE); 515*908f215eSXin LI assert_true(XML_StopParser(parser, resumable) == XML_STATUS_ERROR); 516*908f215eSXin LI assert_true(XML_GetErrorCode(parser) == XML_ERROR_NOT_STARTED); 517*908f215eSXin LI XML_ParserFree(parser); 518*908f215eSXin LI } 519*908f215eSXin LI } 520*908f215eSXin LI END_TEST 521*908f215eSXin LI 5224543ef51SXin LI void 5234543ef51SXin LI make_miscellaneous_test_case(Suite *s) { 5244543ef51SXin LI TCase *tc_misc = tcase_create("miscellaneous tests"); 5254543ef51SXin LI 5264543ef51SXin LI suite_add_tcase(s, tc_misc); 5274543ef51SXin LI tcase_add_checked_fixture(tc_misc, NULL, basic_teardown); 5284543ef51SXin LI 5294543ef51SXin LI tcase_add_test(tc_misc, test_misc_alloc_create_parser); 5304543ef51SXin LI tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding); 5314543ef51SXin LI tcase_add_test(tc_misc, test_misc_null_parser); 5324543ef51SXin LI tcase_add_test(tc_misc, test_misc_error_string); 5334543ef51SXin LI tcase_add_test(tc_misc, test_misc_version); 5344543ef51SXin LI tcase_add_test(tc_misc, test_misc_features); 5354543ef51SXin LI tcase_add_test(tc_misc, test_misc_attribute_leak); 5364543ef51SXin LI tcase_add_test(tc_misc, test_misc_utf16le); 5374543ef51SXin LI tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1); 5384543ef51SXin LI tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2); 5394543ef51SXin LI tcase_add_test__ifdef_xml_dtd( 5404543ef51SXin LI tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317); 5414543ef51SXin LI tcase_add_test(tc_misc, test_misc_tag_mismatch_reset_leak); 5424543ef51SXin LI tcase_add_test(tc_misc, 5434543ef51SXin LI test_misc_create_external_entity_parser_with_null_context); 5444543ef51SXin LI tcase_add_test(tc_misc, test_misc_general_entities_support); 5454543ef51SXin LI tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak); 546*908f215eSXin LI tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing); 547*908f215eSXin LI tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser); 5484543ef51SXin LI } 549