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@users.sourceforge.net> 10 Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net> 11 Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> 12 Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net> 13 Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org> 14 Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk> 15 Copyright (c) 2017 Joe Orton <jorton@redhat.com> 16 Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com> 17 Copyright (c) 2018 Marco Maggi <marco.maggi-ipsu@poste.it> 18 Copyright (c) 2019 David Loffredo <loffredo@steptools.com> 19 Copyright (c) 2020 Tim Gates <tim.gates@iress.com> 20 Copyright (c) 2021 Donghee Na <donghee.na@python.org> 21 Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com> 22 Copyright (c) 2026 Matthew Fernandez <matthew.fernandez@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 SPDX-License-Identifier: MIT 45 */ 46 47 #include "expat_config.h" 48 49 #include <assert.h> 50 #include <errno.h> 51 #include <inttypes.h> // for PRIu64 52 #include <stdint.h> // for SIZE_MAX 53 #include <stdio.h> 54 #include <string.h> 55 56 #include "expat.h" 57 #include "internal.h" 58 #include "chardata.h" 59 #include "minicheck.h" 60 #include "common.h" 61 #include "handlers.h" 62 63 /* Common test data */ 64 65 const char *long_character_data_text 66 = "<?xml version='1.0' encoding='iso-8859-1'?><s>" 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 "012345678901234567890123456789012345678901234567890123456789" 85 "012345678901234567890123456789012345678901234567890123456789" 86 "012345678901234567890123456789012345678901234567890123456789" 87 "</s>"; 88 89 const char *long_cdata_text 90 = "<s><![CDATA[" 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 "012345678901234567890123456789012345678901234567890123456789" 109 "012345678901234567890123456789012345678901234567890123456789" 110 "012345678901234567890123456789012345678901234567890123456789" 111 "]]></s>"; 112 113 /* Having an element name longer than 1024 characters exercises some 114 * of the pool allocation code in the parser that otherwise does not 115 * get executed. The count at the end of the line is the number of 116 * characters (bytes) in the element name by that point.x 117 */ 118 const char *get_buffer_test_text 119 = "<documentwitharidiculouslylongelementnametotease" /* 0x030 */ 120 "aparticularcorneroftheallocationinXML_GetBuffers" /* 0x060 */ 121 "othatwecanimprovethecoverageyetagain012345678901" /* 0x090 */ 122 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0c0 */ 123 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0f0 */ 124 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x120 */ 125 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x150 */ 126 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x180 */ 127 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1b0 */ 128 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1e0 */ 129 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x210 */ 130 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x240 */ 131 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x270 */ 132 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2a0 */ 133 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2d0 */ 134 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x300 */ 135 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x330 */ 136 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x360 */ 137 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x390 */ 138 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3c0 */ 139 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3f0 */ 140 "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */ 141 142 /* Test control globals */ 143 144 /* Used as the "resumable" parameter to XML_StopParser by some tests */ 145 XML_Bool g_resumable = XML_FALSE; 146 147 /* Used to control abort checks in some tests */ 148 XML_Bool g_abortable = XML_FALSE; 149 150 /* Used to control _XML_Parse_SINGLE_BYTES() chunk size */ 151 int g_chunkSize = 1; 152 153 /* Common test functions */ 154 155 void 156 tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) { 157 #ifdef XML_DTD 158 tcase_add_test(tc, test); 159 #else 160 UNUSED_P(tc); 161 UNUSED_P(test); 162 #endif 163 } 164 165 void 166 tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test) { 167 #if XML_GE == 1 168 tcase_add_test(tc, test); 169 #else 170 UNUSED_P(tc); 171 UNUSED_P(test); 172 #endif 173 } 174 175 void 176 basic_teardown(void) { 177 if (g_parser != NULL) { 178 XML_ParserFree(g_parser); 179 g_parser = NULL; 180 } 181 } 182 183 /* Generate a failure using the parser state to create an error message; 184 this should be used when the parser reports an error we weren't 185 expecting. 186 */ 187 void 188 _xml_failure(XML_Parser parser, const char *file, int line) { 189 char buffer[1024]; 190 enum XML_Error err = XML_GetErrorCode(parser); 191 snprintf(buffer, sizeof(buffer), 192 " %d: %" XML_FMT_STR " (line %" PRIu64 ", offset %" PRIu64 193 ")\n reported from %s, line %d\n", 194 err, XML_ErrorString(err), XML_GetCurrentLineNumber64(parser), 195 XML_GetCurrentColumnNumber64(parser), file, line); 196 _fail(file, line, buffer); 197 } 198 199 enum XML_Status 200 _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len, 201 int isFinal) { 202 // This ensures that tests have to run pathological parse cases 203 // (e.g. when `s` is NULL) against plain XML_Parse rather than 204 // chunking _XML_Parse_SINGLE_BYTES. 205 assert((parser != NULL) && (s != NULL) && (len >= 0)); 206 const int chunksize = g_chunkSize; 207 if (chunksize > 0) { 208 // parse in chunks of `chunksize` bytes as long as not exhausting 209 for (; len > chunksize; len -= chunksize, s += chunksize) { 210 enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE); 211 if (res != XML_STATUS_OK) { 212 if ((res == XML_STATUS_SUSPENDED) && (len > chunksize)) { 213 fail("Use of function _XML_Parse_SINGLE_BYTES with a chunk size " 214 "greater than 0 (from g_chunkSize) does not work well with " 215 "suspension. Please consider use of plain XML_Parse at this " 216 "place in your test, instead."); 217 } 218 return res; 219 } 220 } 221 } 222 // parse the final chunk, the size of which will be <= chunksize 223 return XML_Parse(parser, s, len, isFinal); 224 } 225 226 void 227 _expect_failure(const char *text, enum XML_Error errorCode, 228 const char *errorMessage, const char *file, int lineno) { 229 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 230 == XML_STATUS_OK) 231 /* Hackish use of _fail() macro, but lets us report 232 the right filename and line number. */ 233 _fail(file, lineno, errorMessage); 234 if (XML_GetErrorCode(g_parser) != errorCode) 235 _xml_failure(g_parser, file, lineno); 236 } 237 238 void 239 _run_character_check(const char *text, const XML_Char *expected, 240 const char *file, int line) { 241 CharData storage; 242 243 CharData_Init(&storage); 244 XML_SetUserData(g_parser, &storage); 245 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 246 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 247 == XML_STATUS_ERROR) 248 _xml_failure(g_parser, file, line); 249 CharData_CheckXMLChars(&storage, expected); 250 } 251 252 void 253 _run_attribute_check(const char *text, const XML_Char *expected, 254 const char *file, int line) { 255 CharData storage; 256 257 CharData_Init(&storage); 258 XML_SetUserData(g_parser, &storage); 259 XML_SetStartElementHandler(g_parser, accumulate_attribute); 260 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 261 == XML_STATUS_ERROR) 262 _xml_failure(g_parser, file, line); 263 CharData_CheckXMLChars(&storage, expected); 264 } 265 266 void 267 _run_ext_character_check(const char *text, ExtTest *test_data, 268 const XML_Char *expected, const char *file, int line) { 269 CharData *const storage = malloc(sizeof(CharData)); 270 271 CharData_Init(storage); 272 test_data->storage = storage; 273 XML_SetUserData(g_parser, test_data); 274 XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters); 275 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 276 == XML_STATUS_ERROR) 277 _xml_failure(g_parser, file, line); 278 CharData_CheckXMLChars(storage, expected); 279 280 free(storage); 281 } 282 283 /* Control variable; the number of times duff_allocator() will successfully 284 * allocate */ 285 #define ALLOC_ALWAYS_SUCCEED (-1) 286 #define REALLOC_ALWAYS_SUCCEED (-1) 287 288 int g_allocation_count = ALLOC_ALWAYS_SUCCEED; 289 int g_reallocation_count = REALLOC_ALWAYS_SUCCEED; 290 291 /* Crocked allocator for allocation failure tests */ 292 void * 293 duff_allocator(size_t size) { 294 if (g_allocation_count == 0) 295 return NULL; 296 if (g_allocation_count != ALLOC_ALWAYS_SUCCEED) 297 g_allocation_count--; 298 return malloc(size); 299 } 300 301 /* Crocked reallocator for allocation failure tests */ 302 void * 303 duff_reallocator(void *ptr, size_t size) { 304 if (g_reallocation_count == 0) 305 return NULL; 306 if (g_reallocation_count != REALLOC_ALWAYS_SUCCEED) 307 g_reallocation_count--; 308 return realloc(ptr, size); 309 } 310 311 // Portable remake of strnlen(3) for C99 312 static size_t 313 portable_strnlen(const char *s, size_t maxlen) { 314 const char *const end = (const char *)memchr(s, '\0', maxlen); 315 return (end == NULL) ? maxlen : (size_t)(end - s); 316 } 317 318 // Portable remake of strndup(3) for C99 319 char * 320 portable_strndup(const char *s, size_t n) { 321 if ((s == NULL) || (n == SIZE_MAX)) { 322 errno = EINVAL; 323 return NULL; 324 } 325 326 n = portable_strnlen(s, n); 327 328 char *const buffer = malloc(n + 1); 329 if (buffer == NULL) { 330 errno = ENOMEM; 331 return NULL; 332 } 333 334 errno = 0; 335 336 memcpy(buffer, s, n); 337 338 buffer[n] = '\0'; 339 340 return buffer; 341 } 342