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