xref: /freebsd/contrib/expat/tests/misc_tests.c (revision 908f215e80fa482aa953c39afa6bb516f561fc00)
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 '&#37;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;][&amp;&apos;&gt;&lt;&quot;]</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=&amp;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