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