1 /* Commonly used functions for the Expat test suite 2 __ __ _ 3 ___\ \/ /_ __ __ _| |_ 4 / _ \\ /| '_ \ / _` | __| 5 | __// \| |_) | (_| | |_ 6 \___/_/\_\ .__/ \__,_|\__| 7 |_| XML parser 8 9 Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake (at) users.sourceforge.net> 10 Copyright (c) 2003 Greg Stein <gstein (at) users.sourceforge.net> 11 Copyright (c) 2005-2007 Steven Solie <steven (at) solie.ca> 12 Copyright (c) 2005-2012 Karl Waclawek <karl (at) waclawek.net> 13 Copyright (c) 2016-2026 Sebastian Pipping <sebastian (at) pipping.org> 14 Copyright (c) 2017-2022 Rhodri James <rhodri (at) wildebeest.org.uk> 15 Copyright (c) 2017 Joe Orton <jorton (at) redhat.com> 16 Copyright (c) 2017 Jos Gutirrez de la Concha <jose (at) zeroc.com> 17 Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu (at) poste.it> 18 Copyright (c) 2019 David Loffredo <loffredo (at) steptools.com> 19 Copyright (c) 2020 Tim Gates <tim.gates (at) iress.com> 20 Copyright (c) 2021 Donghee Na <donghee.na (at) python.org> 21 Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild (at) sony.com> 22 Copyright (c) 2026 Matthew Fernandez <matthew.fernandez (at) gmail.com> 23 Licensed under the MIT license: 24 25 Permission is hereby granted, free of charge, to any person obtaining 26 a copy of this software and associated documentation files (the 27 "Software"), to deal in the Software without restriction, including 28 without limitation the rights to use, copy, modify, merge, publish, 29 distribute, sublicense, and/or sell copies of the Software, and to permit 30 persons to whom the Software is furnished to do so, subject to the 31 following conditions: 32 33 The above copyright notice and this permission notice shall be included 34 in all copies or substantial portions of the Software. 35 36 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 37 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 38 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 39 NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 40 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 41 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 42 USE OR OTHER DEALINGS IN THE SOFTWARE. 43 */ 44 45 #include "expat_config.h" 46 47 #include <assert.h> 48 #include <errno.h> 49 #include <stdint.h> // for SIZE_MAX 50 #include <stdio.h> 51 #include <string.h> 52 53 #include "expat.h" 54 #include "internal.h" 55 #include "chardata.h" 56 #include "minicheck.h" 57 #include "common.h" 58 #include "handlers.h" 59 60 /* Common test data */ 61 62 const char *long_character_data_text 63 = "<?xml version='1.0' encoding='iso-8859-1'?><s>" 64 "012345678901234567890123456789012345678901234567890123456789" 65 "012345678901234567890123456789012345678901234567890123456789" 66 "012345678901234567890123456789012345678901234567890123456789" 67 "012345678901234567890123456789012345678901234567890123456789" 68 "012345678901234567890123456789012345678901234567890123456789" 69 "012345678901234567890123456789012345678901234567890123456789" 70 "012345678901234567890123456789012345678901234567890123456789" 71 "012345678901234567890123456789012345678901234567890123456789" 72 "012345678901234567890123456789012345678901234567890123456789" 73 "012345678901234567890123456789012345678901234567890123456789" 74 "012345678901234567890123456789012345678901234567890123456789" 75 "012345678901234567890123456789012345678901234567890123456789" 76 "012345678901234567890123456789012345678901234567890123456789" 77 "012345678901234567890123456789012345678901234567890123456789" 78 "012345678901234567890123456789012345678901234567890123456789" 79 "012345678901234567890123456789012345678901234567890123456789" 80 "012345678901234567890123456789012345678901234567890123456789" 81 "012345678901234567890123456789012345678901234567890123456789" 82 "012345678901234567890123456789012345678901234567890123456789" 83 "012345678901234567890123456789012345678901234567890123456789" 84 "</s>"; 85 86 const char *long_cdata_text 87 = "<s><![CDATA[" 88 "012345678901234567890123456789012345678901234567890123456789" 89 "012345678901234567890123456789012345678901234567890123456789" 90 "012345678901234567890123456789012345678901234567890123456789" 91 "012345678901234567890123456789012345678901234567890123456789" 92 "012345678901234567890123456789012345678901234567890123456789" 93 "012345678901234567890123456789012345678901234567890123456789" 94 "012345678901234567890123456789012345678901234567890123456789" 95 "012345678901234567890123456789012345678901234567890123456789" 96 "012345678901234567890123456789012345678901234567890123456789" 97 "012345678901234567890123456789012345678901234567890123456789" 98 "012345678901234567890123456789012345678901234567890123456789" 99 "012345678901234567890123456789012345678901234567890123456789" 100 "012345678901234567890123456789012345678901234567890123456789" 101 "012345678901234567890123456789012345678901234567890123456789" 102 "012345678901234567890123456789012345678901234567890123456789" 103 "012345678901234567890123456789012345678901234567890123456789" 104 "012345678901234567890123456789012345678901234567890123456789" 105 "012345678901234567890123456789012345678901234567890123456789" 106 "012345678901234567890123456789012345678901234567890123456789" 107 "012345678901234567890123456789012345678901234567890123456789" 108 "]]></s>"; 109 110 /* Having an element name longer than 1024 characters exercises some 111 * of the pool allocation code in the parser that otherwise does not 112 * get executed. The count at the end of the line is the number of 113 * characters (bytes) in the element name by that point.x 114 */ 115 const char *get_buffer_test_text 116 = "<documentwitharidiculouslylongelementnametotease" /* 0x030 */ 117 "aparticularcorneroftheallocationinXML_GetBuffers" /* 0x060 */ 118 "othatwecanimprovethecoverageyetagain012345678901" /* 0x090 */ 119 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0c0 */ 120 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0f0 */ 121 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x120 */ 122 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x150 */ 123 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x180 */ 124 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1b0 */ 125 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1e0 */ 126 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x210 */ 127 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x240 */ 128 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x270 */ 129 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2a0 */ 130 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2d0 */ 131 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x300 */ 132 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x330 */ 133 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x360 */ 134 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x390 */ 135 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3c0 */ 136 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3f0 */ 137 "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */ 138 139 /* Test control globals */ 140 141 /* Used as the "resumable" parameter to XML_StopParser by some tests */ 142 XML_Bool g_resumable = XML_FALSE; 143 144 /* Used to control abort checks in some tests */ 145 XML_Bool g_abortable = XML_FALSE; 146 147 /* Used to control _XML_Parse_SINGLE_BYTES() chunk size */ 148 int g_chunkSize = 1; 149 150 /* Common test functions */ 151 152 void 153 tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) { 154 #ifdef XML_DTD 155 tcase_add_test(tc, test); 156 #else 157 UNUSED_P(tc); 158 UNUSED_P(test); 159 #endif 160 } 161 162 void 163 tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test) { 164 #if XML_GE == 1 165 tcase_add_test(tc, test); 166 #else 167 UNUSED_P(tc); 168 UNUSED_P(test); 169 #endif 170 } 171 172 void 173 basic_teardown(void) { 174 if (g_parser != NULL) { 175 XML_ParserFree(g_parser); 176 g_parser = NULL; 177 } 178 } 179 180 /* Generate a failure using the parser state to create an error message; 181 this should be used when the parser reports an error we weren't 182 expecting. 183 */ 184 void 185 _xml_failure(XML_Parser parser, const char *file, int line) { 186 char buffer[1024]; 187 enum XML_Error err = XML_GetErrorCode(parser); 188 snprintf(buffer, sizeof(buffer), 189 " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD 190 "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n", 191 err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser), 192 XML_GetCurrentColumnNumber(parser), file, line); 193 _fail(file, line, buffer); 194 } 195 196 enum XML_Status 197 _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len, 198 int isFinal) { 199 // This ensures that tests have to run pathological parse cases 200 // (e.g. when `s` is NULL) against plain XML_Parse rather than 201 // chunking _XML_Parse_SINGLE_BYTES. 202 assert((parser != NULL) && (s != NULL) && (len >= 0)); 203 const int chunksize = g_chunkSize; 204 if (chunksize > 0) { 205 // parse in chunks of `chunksize` bytes as long as not exhausting 206 for (; len > chunksize; len -= chunksize, s += chunksize) { 207 enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE); 208 if (res != XML_STATUS_OK) { 209 if ((res == XML_STATUS_SUSPENDED) && (len > chunksize)) { 210 fail("Use of function _XML_Parse_SINGLE_BYTES with a chunk size " 211 "greater than 0 (from g_chunkSize) does not work well with " 212 "suspension. Please consider use of plain XML_Parse at this " 213 "place in your test, instead."); 214 } 215 return res; 216 } 217 } 218 } 219 // parse the final chunk, the size of which will be <= chunksize 220 return XML_Parse(parser, s, len, isFinal); 221 } 222 223 void 224 _expect_failure(const char *text, enum XML_Error errorCode, 225 const char *errorMessage, const char *file, int lineno) { 226 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 227 == XML_STATUS_OK) 228 /* Hackish use of _fail() macro, but lets us report 229 the right filename and line number. */ 230 _fail(file, lineno, errorMessage); 231 if (XML_GetErrorCode(g_parser) != errorCode) 232 _xml_failure(g_parser, file, lineno); 233 } 234 235 void 236 _run_character_check(const char *text, const XML_Char *expected, 237 const char *file, int line) { 238 CharData storage; 239 240 CharData_Init(&storage); 241 XML_SetUserData(g_parser, &storage); 242 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 243 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 244 == XML_STATUS_ERROR) 245 _xml_failure(g_parser, file, line); 246 CharData_CheckXMLChars(&storage, expected); 247 } 248 249 void 250 _run_attribute_check(const char *text, const XML_Char *expected, 251 const char *file, int line) { 252 CharData storage; 253 254 CharData_Init(&storage); 255 XML_SetUserData(g_parser, &storage); 256 XML_SetStartElementHandler(g_parser, accumulate_attribute); 257 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 258 == XML_STATUS_ERROR) 259 _xml_failure(g_parser, file, line); 260 CharData_CheckXMLChars(&storage, expected); 261 } 262 263 void 264 _run_ext_character_check(const char *text, ExtTest *test_data, 265 const XML_Char *expected, const char *file, int line) { 266 CharData *const storage = malloc(sizeof(CharData)); 267 268 CharData_Init(storage); 269 test_data->storage = storage; 270 XML_SetUserData(g_parser, test_data); 271 XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters); 272 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 273 == XML_STATUS_ERROR) 274 _xml_failure(g_parser, file, line); 275 CharData_CheckXMLChars(storage, expected); 276 277 free(storage); 278 } 279 280 /* Control variable; the number of times duff_allocator() will successfully 281 * allocate */ 282 #define ALLOC_ALWAYS_SUCCEED (-1) 283 #define REALLOC_ALWAYS_SUCCEED (-1) 284 285 int g_allocation_count = ALLOC_ALWAYS_SUCCEED; 286 int g_reallocation_count = REALLOC_ALWAYS_SUCCEED; 287 288 /* Crocked allocator for allocation failure tests */ 289 void * 290 duff_allocator(size_t size) { 291 if (g_allocation_count == 0) 292 return NULL; 293 if (g_allocation_count != ALLOC_ALWAYS_SUCCEED) 294 g_allocation_count--; 295 return malloc(size); 296 } 297 298 /* Crocked reallocator for allocation failure tests */ 299 void * 300 duff_reallocator(void *ptr, size_t size) { 301 if (g_reallocation_count == 0) 302 return NULL; 303 if (g_reallocation_count != REALLOC_ALWAYS_SUCCEED) 304 g_reallocation_count--; 305 return realloc(ptr, size); 306 } 307 308 // Portable remake of strnlen(3) for C99 309 static size_t 310 portable_strnlen(const char *s, size_t maxlen) { 311 const char *const end = (const char *)memchr(s, '\0', maxlen); 312 return (end == NULL) ? maxlen : (size_t)(end - s); 313 } 314 315 // Portable remake of strndup(3) for C99 316 char * 317 portable_strndup(const char *s, size_t n) { 318 if ((s == NULL) || (n == SIZE_MAX)) { 319 errno = EINVAL; 320 return NULL; 321 } 322 323 n = portable_strnlen(s, n); 324 325 char *const buffer = malloc(n + 1); 326 if (buffer == NULL) { 327 errno = ENOMEM; 328 return NULL; 329 } 330 331 errno = 0; 332 333 memcpy(buffer, s, n); 334 335 buffer[n] = '\0'; 336 337 return buffer; 338 } 339