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
57 const 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
81 const 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 */
110 const 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 */
137 XML_Bool g_resumable = XML_FALSE;
138
139 /* Used to control abort checks in some tests */
140 XML_Bool g_abortable = XML_FALSE;
141
142 /* Used to control _XML_Parse_SINGLE_BYTES() chunk size */
143 int g_chunkSize = 1;
144
145 /* Common test functions */
146
147 void
tcase_add_test__ifdef_xml_dtd(TCase * tc,tcase_test_function test)148 tcase_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
157 void
tcase_add_test__if_xml_ge(TCase * tc,tcase_test_function test)158 tcase_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
167 void
basic_teardown(void)168 basic_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 */
179 void
_xml_failure(XML_Parser parser,const char * file,int line)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
191 enum XML_Status
_XML_Parse_SINGLE_BYTES(XML_Parser parser,const char * s,int len,int isFinal)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
212 void
_expect_failure(const char * text,enum XML_Error errorCode,const char * errorMessage,const char * file,int lineno)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 */
227 void XMLCALL
accumulate_characters(void * userData,const XML_Char * s,int len)228 accumulate_characters(void *userData, const XML_Char *s, int len) {
229 CharData_AppendXMLChars((CharData *)userData, s, len);
230 }
231
232 void XMLCALL
accumulate_attribute(void * userData,const XML_Char * name,const XML_Char ** atts)233 accumulate_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
248 void
_run_character_check(const char * text,const XML_Char * expected,const char * file,int line)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
262 void
_run_attribute_check(const char * text,const XML_Char * expected,const char * file,int line)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
276 void XMLCALL
ext_accumulate_characters(void * userData,const XML_Char * s,int len)277 ext_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
282 void
_run_ext_character_check(const char * text,ExtTest * test_data,const XML_Char * expected,const char * file,int line)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
304 int g_allocation_count = ALLOC_ALWAYS_SUCCEED;
305 int g_reallocation_count = REALLOC_ALWAYS_SUCCEED;
306
307 /* Crocked allocator for allocation failure tests */
308 void *
duff_allocator(size_t size)309 duff_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 */
318 void *
duff_reallocator(void * ptr,size_t size)319 duff_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