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-2025 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 Licensed under the MIT license: 23 24 Permission is hereby granted, free of charge, to any person obtaining 25 a copy of this software and associated documentation files (the 26 "Software"), to deal in the Software without restriction, including 27 without limitation the rights to use, copy, modify, merge, publish, 28 distribute, sublicense, and/or sell copies of the Software, and to permit 29 persons to whom the Software is furnished to do so, subject to the 30 following conditions: 31 32 The above copyright notice and this permission notice shall be included 33 in all copies or substantial portions of the Software. 34 35 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 36 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 37 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 38 NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 39 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 40 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 41 USE OR OTHER DEALINGS IN THE SOFTWARE. 42 */ 43 44 #include <assert.h> 45 #include <errno.h> 46 #include <stdint.h> // for SIZE_MAX 47 #include <stdio.h> 48 #include <string.h> 49 50 #include "expat_config.h" 51 #include "expat.h" 52 #include "internal.h" 53 #include "chardata.h" 54 #include "minicheck.h" 55 #include "common.h" 56 #include "handlers.h" 57 58 /* Common test data */ 59 60 const char *long_character_data_text 61 = "<?xml version='1.0' encoding='iso-8859-1'?><s>" 62 "012345678901234567890123456789012345678901234567890123456789" 63 "012345678901234567890123456789012345678901234567890123456789" 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 "</s>"; 83 84 const char *long_cdata_text 85 = "<s><![CDATA[" 86 "012345678901234567890123456789012345678901234567890123456789" 87 "012345678901234567890123456789012345678901234567890123456789" 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 "]]></s>"; 107 108 /* Having an element name longer than 1024 characters exercises some 109 * of the pool allocation code in the parser that otherwise does not 110 * get executed. The count at the end of the line is the number of 111 * characters (bytes) in the element name by that point.x 112 */ 113 const char *get_buffer_test_text 114 = "<documentwitharidiculouslylongelementnametotease" /* 0x030 */ 115 "aparticularcorneroftheallocationinXML_GetBuffers" /* 0x060 */ 116 "othatwecanimprovethecoverageyetagain012345678901" /* 0x090 */ 117 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0c0 */ 118 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0f0 */ 119 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x120 */ 120 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x150 */ 121 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x180 */ 122 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1b0 */ 123 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1e0 */ 124 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x210 */ 125 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x240 */ 126 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x270 */ 127 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2a0 */ 128 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2d0 */ 129 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x300 */ 130 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x330 */ 131 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x360 */ 132 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x390 */ 133 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3c0 */ 134 "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3f0 */ 135 "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */ 136 137 /* Test control globals */ 138 139 /* Used as the "resumable" parameter to XML_StopParser by some tests */ 140 XML_Bool g_resumable = XML_FALSE; 141 142 /* Used to control abort checks in some tests */ 143 XML_Bool g_abortable = XML_FALSE; 144 145 /* Used to control _XML_Parse_SINGLE_BYTES() chunk size */ 146 int g_chunkSize = 1; 147 148 /* Common test functions */ 149 150 void 151 tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) { 152 #ifdef XML_DTD 153 tcase_add_test(tc, test); 154 #else 155 UNUSED_P(tc); 156 UNUSED_P(test); 157 #endif 158 } 159 160 void 161 tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test) { 162 #if XML_GE == 1 163 tcase_add_test(tc, test); 164 #else 165 UNUSED_P(tc); 166 UNUSED_P(test); 167 #endif 168 } 169 170 void 171 basic_teardown(void) { 172 if (g_parser != NULL) { 173 XML_ParserFree(g_parser); 174 g_parser = NULL; 175 } 176 } 177 178 /* Generate a failure using the parser state to create an error message; 179 this should be used when the parser reports an error we weren't 180 expecting. 181 */ 182 void 183 _xml_failure(XML_Parser parser, const char *file, int line) { 184 char buffer[1024]; 185 enum XML_Error err = XML_GetErrorCode(parser); 186 snprintf(buffer, sizeof(buffer), 187 " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD 188 "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n", 189 err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser), 190 XML_GetCurrentColumnNumber(parser), file, line); 191 _fail(file, line, buffer); 192 } 193 194 enum XML_Status 195 _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len, 196 int isFinal) { 197 // This ensures that tests have to run pathological parse cases 198 // (e.g. when `s` is NULL) against plain XML_Parse rather than 199 // chunking _XML_Parse_SINGLE_BYTES. 200 assert((parser != NULL) && (s != NULL) && (len >= 0)); 201 const int chunksize = g_chunkSize; 202 if (chunksize > 0) { 203 // parse in chunks of `chunksize` bytes as long as not exhausting 204 for (; len > chunksize; len -= chunksize, s += chunksize) { 205 enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE); 206 if (res != XML_STATUS_OK) { 207 if ((res == XML_STATUS_SUSPENDED) && (len > chunksize)) { 208 fail("Use of function _XML_Parse_SINGLE_BYTES with a chunk size " 209 "greater than 0 (from g_chunkSize) does not work well with " 210 "suspension. Please consider use of plain XML_Parse at this " 211 "place in your test, instead."); 212 } 213 return res; 214 } 215 } 216 } 217 // parse the final chunk, the size of which will be <= chunksize 218 return XML_Parse(parser, s, len, isFinal); 219 } 220 221 void 222 _expect_failure(const char *text, enum XML_Error errorCode, 223 const char *errorMessage, const char *file, int lineno) { 224 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 225 == XML_STATUS_OK) 226 /* Hackish use of _fail() macro, but lets us report 227 the right filename and line number. */ 228 _fail(file, lineno, errorMessage); 229 if (XML_GetErrorCode(g_parser) != errorCode) 230 _xml_failure(g_parser, file, lineno); 231 } 232 233 void 234 _run_character_check(const char *text, const XML_Char *expected, 235 const char *file, int line) { 236 CharData storage; 237 238 CharData_Init(&storage); 239 XML_SetUserData(g_parser, &storage); 240 XML_SetCharacterDataHandler(g_parser, accumulate_characters); 241 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 242 == XML_STATUS_ERROR) 243 _xml_failure(g_parser, file, line); 244 CharData_CheckXMLChars(&storage, expected); 245 } 246 247 void 248 _run_attribute_check(const char *text, const XML_Char *expected, 249 const char *file, int line) { 250 CharData storage; 251 252 CharData_Init(&storage); 253 XML_SetUserData(g_parser, &storage); 254 XML_SetStartElementHandler(g_parser, accumulate_attribute); 255 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 256 == XML_STATUS_ERROR) 257 _xml_failure(g_parser, file, line); 258 CharData_CheckXMLChars(&storage, expected); 259 } 260 261 void 262 _run_ext_character_check(const char *text, ExtTest *test_data, 263 const XML_Char *expected, const char *file, int line) { 264 CharData *const storage = (CharData *)malloc(sizeof(CharData)); 265 266 CharData_Init(storage); 267 test_data->storage = storage; 268 XML_SetUserData(g_parser, test_data); 269 XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters); 270 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) 271 == XML_STATUS_ERROR) 272 _xml_failure(g_parser, file, line); 273 CharData_CheckXMLChars(storage, expected); 274 275 free(storage); 276 } 277 278 /* Control variable; the number of times duff_allocator() will successfully 279 * allocate */ 280 #define ALLOC_ALWAYS_SUCCEED (-1) 281 #define REALLOC_ALWAYS_SUCCEED (-1) 282 283 int g_allocation_count = ALLOC_ALWAYS_SUCCEED; 284 int g_reallocation_count = REALLOC_ALWAYS_SUCCEED; 285 286 /* Crocked allocator for allocation failure tests */ 287 void * 288 duff_allocator(size_t size) { 289 if (g_allocation_count == 0) 290 return NULL; 291 if (g_allocation_count != ALLOC_ALWAYS_SUCCEED) 292 g_allocation_count--; 293 return malloc(size); 294 } 295 296 /* Crocked reallocator for allocation failure tests */ 297 void * 298 duff_reallocator(void *ptr, size_t size) { 299 if (g_reallocation_count == 0) 300 return NULL; 301 if (g_reallocation_count != REALLOC_ALWAYS_SUCCEED) 302 g_reallocation_count--; 303 return realloc(ptr, size); 304 } 305 306 // Portable remake of strndup(3) for C99; does not care about space efficiency 307 char * 308 portable_strndup(const char *s, size_t n) { 309 if ((s == NULL) || (n == SIZE_MAX)) { 310 errno = EINVAL; 311 return NULL; 312 } 313 314 char *const buffer = (char *)malloc(n + 1); 315 if (buffer == NULL) { 316 errno = ENOMEM; 317 return NULL; 318 } 319 320 errno = 0; 321 322 memcpy(buffer, s, n); 323 324 buffer[n] = '\0'; 325 326 return buffer; 327 } 328