Home | History | Annotate | Line # | Download | only in tests
      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