xref: /freebsd/contrib/expat/tests/common.c (revision dece5b05f577fc4c6b89af7ad48dfbdf7cc4945c)
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