Apache HTTPD
misc_tests.c
Go to the documentation of this file.
1/* Tests in the "miscellaneous" test case for the Expat test suite
2 __ __ _
3 ___\ \/ /_ __ __ _| |_
4 / _ \\ /| '_ \ / _` | __|
5 | __// \| |_) | (_| | |_
6 \___/_/\_\ .__/ \__,_|\__|
7 |_| XML parser
8
9 Copyright (c) 2001-2006 Fred L. Drake, Jr. <[email protected]>
10 Copyright (c) 2003 Greg Stein <[email protected]>
11 Copyright (c) 2005-2007 Steven Solie <[email protected]>
12 Copyright (c) 2005-2012 Karl Waclawek <[email protected]>
13 Copyright (c) 2016-2024 Sebastian Pipping <[email protected]>
14 Copyright (c) 2017-2022 Rhodri James <[email protected]>
15 Copyright (c) 2017 Joe Orton <[email protected]>
16 Copyright (c) 2017 José Gutiérrez de la Concha <[email protected]>
17 Copyright (c) 2018 Marco Maggi <[email protected]>
18 Copyright (c) 2019 David Loffredo <[email protected]>
19 Copyright (c) 2020 Tim Gates <[email protected]>
20 Copyright (c) 2021 Donghee Na <[email protected]>
21 Copyright (c) 2023 Sony Corporation / Snild Dolkow <[email protected]>
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#if defined(NDEBUG)
45# undef NDEBUG /* because test suite relies on assert(...) at the moment */
46#endif
47
48#include <assert.h>
49#include <string.h>
50
51#include "expat_config.h"
52
53#include "expat.h"
54#include "internal.h"
55#include "minicheck.h"
56#include "memcheck.h"
57#include "common.h"
58#include "ascii.h" /* for ASCII_xxx */
59#include "handlers.h"
60#include "misc_tests.h"
61
62/* Test that a failure to allocate the parser structure fails gracefully */
65 unsigned int i;
66 const unsigned int max_alloc_count = 10;
67
68 /* Something this simple shouldn't need more than 10 allocations */
69 for (i = 0; i < max_alloc_count; i++) {
72 if (g_parser != NULL)
73 break;
74 }
75 if (i == 0)
76 fail("Parser unexpectedly ignored failing allocator");
77 else if (i == max_alloc_count)
78 fail("Parser not created with max allocation count");
79}
81
82/* Test memory allocation failures for a parser with an encoding */
85 unsigned int i;
86 const unsigned int max_alloc_count = 10;
87
88 /* Try several levels of allocation */
89 for (i = 0; i < max_alloc_count; i++) {
92 if (g_parser != NULL)
93 break;
94 }
95 if (i == 0)
96 fail("Parser ignored failing allocator");
97 else if (i == max_alloc_count)
98 fail("Parser not created with max allocation count");
99}
101
102/* Test that freeing a NULL parser doesn't cause an explosion.
103 * (Not actually tested anywhere else)
104 */
109
110#if defined(__has_feature)
111# if __has_feature(undefined_behavior_sanitizer)
112# define EXPAT_TESTS_UBSAN 1
113# else
114# define EXPAT_TESTS_UBSAN 0
115# endif
116#else
117# define EXPAT_TESTS_UBSAN 0
118#endif
119
120/* Test that XML_ErrorString rejects out-of-range codes */
122#if ! EXPAT_TESTS_UBSAN // because this would trigger UBSan
123 union {
124 enum XML_Error xml_error;
125 int integer;
126 } trickery;
127
128 assert_true(sizeof(enum XML_Error) == sizeof(int)); // self-test
129
130 trickery.integer = -1;
131 if (XML_ErrorString(trickery.xml_error) != NULL)
132 fail("Negative error code not rejected");
133
134 trickery.integer = 100;
135 if (XML_ErrorString(trickery.xml_error) != NULL)
136 fail("Large error code not rejected");
137#endif
138}
140
141/* Test the version information is consistent */
142
143/* Since we are working in XML_LChars (potentially 16-bits), we
144 * can't use the standard C library functions for character
145 * manipulation and have to roll our own.
146 */
147static int
150 if (! version_text)
151 return XML_FALSE;
152
153 while (*version_text != 0x00) {
155 break;
156 version_text++;
157 }
158 if (*version_text == 0x00)
159 return XML_FALSE;
160
161 /* version_struct->major = strtoul(version_text, 10, &version_text) */
162 version_struct->major = 0;
163 while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
164 version_struct->major
165 = 10 * version_struct->major + (*version_text++ - ASCII_0);
166 }
167 if (*version_text++ != ASCII_PERIOD)
168 return XML_FALSE;
169
170 /* Now for the minor version number */
171 version_struct->minor = 0;
172 while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
173 version_struct->minor
174 = 10 * version_struct->minor + (*version_text++ - ASCII_0);
175 }
176 if (*version_text++ != ASCII_PERIOD)
177 return XML_FALSE;
178
179 /* Finally the micro version number */
180 version_struct->micro = 0;
181 while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
182 version_struct->micro
183 = 10 * version_struct->micro + (*version_text++ - ASCII_0);
184 }
185 if (*version_text != 0x00)
186 return XML_FALSE;
187 return XML_TRUE;
188}
189
190static int
192 const XML_Expat_Version *second) {
193 return (first->major == second->major && first->minor == second->minor
194 && first->micro == second->micro);
195}
196
199 /* Silence compiler warning with the following assignment */
202
203 if (version_text == NULL)
204 fail("Could not obtain version text");
207 fail("Unable to parse version text");
209 fail("Version mismatch");
210
211 if (xcstrcmp(version_text, XCS("expat_2.6.4"))) /* needs bump on releases */
212 fail("XML_*_VERSION in expat.h out of sync?\n");
213}
215
216/* Test feature information */
219
220 /* Prevent problems with double-freeing parsers */
221 g_parser = NULL;
222 if (features == NULL) {
223 fail("Failed to get feature information");
224 } else {
225 /* Loop through the features checking what we can */
226 while (features->feature != XML_FEATURE_END) {
227 switch (features->feature) {
229 if (features->value != sizeof(XML_Char))
230 fail("Incorrect size of XML_Char");
231 break;
233 if (features->value != sizeof(XML_LChar))
234 fail("Incorrect size of XML_LChar");
235 break;
236 default:
237 break;
238 }
239 features++;
240 }
241 }
242}
244
245/* Regression test for GitHub Issue #17: memory leak parsing attribute
246 * values with mixed bound and unbound namespaces.
247 */
249 const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
252
253 g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
254 expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
256 /* Prevent the teardown trying to double free */
257 g_parser = NULL;
258
259 if (! tracking_report())
260 fail("Memory leak found");
261}
263
264/* Test parser created for UTF-16LE is successful */
266 const char text[] =
267 /* <?xml version='1.0'?><q>Hi</q> */
268 "<\0?\0x\0m\0l\0 \0"
269 "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
270 "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
271 const XML_Char *expected = XCS("Hi");
273
274 g_parser = XML_ParserCreate(XCS("UTF-16LE"));
275 if (g_parser == NULL)
276 fail("Parser not created");
277
281 if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
285}
287
291 enum XML_Status result;
292 const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
293
297 mydata->parser = parser;
298 mydata->deep = 0;
300
301 result = _XML_Parse_SINGLE_BYTES(parser, doc1, (int)strlen(doc1), 1);
303 free(mydata);
305 fail("Stopping the parser did not work as expected");
306}
308
312 enum XML_Status result;
313 const char *const doc2 = "<doc><elem/></doc>";
314
318 mydata->parser = parser;
319 mydata->deep = 0;
321
322 result = _XML_Parse_SINGLE_BYTES(parser, doc2, (int)strlen(doc2), 1);
324 free(mydata);
326 fail("Stopping the parser did not work as expected");
327}
329
331 const char *const inputOne = "<!DOCTYPE d [\n"
332 "<!ENTITY % e ']><d/>'>\n"
333 "\n"
334 "%e;";
335 const char *const inputTwo
336 = "<!DOCTYPE d [\n"
337 "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&#37;e1;'>\n"
338 "\n"
339 "%e2;";
340 const char *const inputThree = "<!DOCTYPE d [\n"
341 "<!ENTITY % e ']><d'>\n"
342 "\n"
343 "%e;/>";
344 const char *const inputIssue317 = "<!DOCTYPE doc [\n"
345 "<!ENTITY % foo ']>\n"
346 "<doc>Hell<oc (#PCDATA)*>'>\n"
347 "%foo;\n"
348 "]>\n"
349 "<doc>Hello, world</dVc>";
350
351 const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
352 size_t inputIndex = 0;
353
354 for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
359 XML_Size lineNumber;
360 XML_Size columnNumber;
361 const char *const input = inputs[inputIndex];
362
366 if (setParamEntityResult != 1)
367 fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
368
373 fail("Parsing was expected to fail but succeeded.");
374 }
375 }
376
378 fail("Error code does not match XML_ERROR_INVALID_TOKEN");
379
380 lineNumber = XML_GetCurrentLineNumber(parser);
381 if (lineNumber != 4)
382 fail("XML_GetCurrentLineNumber does not work as expected.");
383
384 columnNumber = XML_GetCurrentColumnNumber(parser);
385 if (columnNumber != 0)
386 fail("XML_GetCurrentColumnNumber does not work as expected.");
387
389 }
390}
392
394#ifdef XML_NS
395 const char *const text = "<open xmlns='https://namespace1.test'></close>";
397
398 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
400 fail("Call to parse was expected to fail");
402 fail("Call to parse was expected to fail from a closing tag mismatch");
403
405
406 if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
408 fail("Call to parse was expected to fail");
410 fail("Call to parse was expected to fail from a closing tag mismatch");
411
413#endif
414}
416
418 // With XML_DTD undefined, the only supported case of external entities
419 // is pattern "<!ENTITY entity123 SYSTEM 'filename123'>". A NULL context
420 // was causing a segfault through a null pointer dereference in function
421 // setContext, previously.
424#ifdef XML_DTD
427#else
429#endif /* XML_DTD */
431}
433
435 const char *const doc
436 = "<!DOCTYPE r [\n"
437 "<!ENTITY e1 'v1'>\n"
438 "<!ENTITY e2 SYSTEM 'v2'>\n"
439 "]>\n"
440 "<r a1='[&e1;]'>[&e1;][&e2;][&amp;&apos;&gt;&lt;&quot;]</r>";
441
444
452
453 if (_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc), XML_TRUE)
454 != XML_STATUS_OK) {
456 }
457
459
461 /* clang-format off */
462#if XML_GE == 1
463 XCS("e1=v1\n")
464 XCS("e2=(null)\n")
465 XCS("(r(a1=[v1]))\n")
466 XCS("[v1][][&'><\"]")
467#else
468 XCS("e1=&amp;e1;\n")
469 XCS("e2=(null)\n")
470 XCS("(r(a1=[&e1;]))\n")
471 XCS("[&e1;][&e2;][&'><\"]")
472#endif
473 );
474 /* clang-format on */
475}
477
478static void XMLCALL
480 int len) {
481 UNUSED_P(s);
482 UNUSED_P(len);
483 XML_Parser parser = (XML_Parser)userData;
485}
486
487// NOTE: This test needs active LeakSanitizer to be of actual use
499
508
521
522void
const char apr_size_t len
Definition ap_regex.h:187
void tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test)
Definition common.c:149
void basic_teardown(void)
Definition common.c:169
enum XML_Status _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len, int isFinal)
Definition common.c:193
int g_allocation_count
Definition common.c:275
void * duff_allocator(size_t size)
Definition common.c:280
#define ASCII_PERIOD
Definition ascii.h:108
#define ASCII_9
Definition ascii.h:99
#define ASCII_0
Definition ascii.h:90
void CharData_Init(CharData *storage)
Definition chardata.c:61
int CharData_CheckXMLChars(CharData *storage, const XML_Char *expected)
Definition chardata.c:87
#define XCS(s)
Definition common.h:77
XML_Parser g_parser
Definition runtests.c:62
#define expect_failure(text, errorCode, errorMessage)
Definition common.h:108
#define xcstrcmp(s, t)
Definition common.h:75
#define xml_failure(parser)
Definition common.h:99
const XML_LChar * XML_ErrorString(enum XML_Error code)
Definition xmlparse.c:2429
#define XML_FALSE
Definition expat.h:59
#define XML_STATUS_ERROR
Definition expat.h:76
void XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end)
Definition xmlparse.c:1691
@ XML_FEATURE_SIZEOF_XML_LCHAR
Definition expat.h:1027
@ XML_FEATURE_SIZEOF_XML_CHAR
Definition expat.h:1026
@ XML_FEATURE_END
Definition expat.h:1020
void XML_SetStartElementHandler(XML_Parser parser, XML_StartElementHandler handler)
Definition xmlparse.c:1700
unsigned char XML_Bool
Definition expat.h:57
void XML_SetCharacterDataHandler(XML_Parser parser, XML_CharacterDataHandler handler)
Definition xmlparse.c:1712
XML_Bool XML_ParserReset(XML_Parser parser, const XML_Char *encoding)
Definition xmlparse.c:1286
XML_Error
Definition expat.h:83
@ XML_ERROR_NONE
Definition expat.h:84
@ XML_ERROR_TAG_MISMATCH
Definition expat.h:91
@ XML_ERROR_NOT_STARTED
Definition expat.h:135
@ XML_ERROR_UNBOUND_PREFIX
Definition expat.h:112
@ XML_ERROR_INVALID_TOKEN
Definition expat.h:88
void XML_SetEntityDeclHandler(XML_Parser parser, XML_EntityDeclHandler handler)
Definition xmlparse.c:1883
const XML_Feature * XML_GetFeatureList(void)
Definition xmlparse.c:2567
enum XML_Status XML_StopParser(XML_Parser parser, XML_Bool resumable)
Definition xmlparse.c:2234
enum XML_Error XML_GetErrorCode(XML_Parser parser)
Definition xmlparse.c:2318
@ XML_PARAM_ENTITY_PARSING_ALWAYS
Definition expat.h:883
XML_Parser XML_ParserCreate(const XML_Char *encoding)
Definition xmlparse.c:766
void XML_ParserFree(XML_Parser parser)
Definition xmlparse.c:1537
XML_Size XML_GetCurrentLineNumber(XML_Parser parser)
Definition xmlparse.c:2364
struct XML_ParserStruct * XML_Parser
Definition expat.h:55
XML_Size XML_GetCurrentColumnNumber(XML_Parser parser)
Definition xmlparse.c:2376
void XML_SetUserData(XML_Parser parser, void *userData)
Definition xmlparse.c:1637
#define XML_STATUS_OK
Definition expat.h:78
XML_Parser XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator)
Definition xmlparse.c:771
void XML_SetExternalEntityRefHandler(XML_Parser parser, XML_ExternalEntityRefHandler handler)
Definition xmlparse.c:1838
void * XML_GetBuffer(XML_Parser parser, int len)
Definition xmlparse.c:2108
const XML_LChar * XML_ExpatVersion(void)
Definition xmlparse.c:2537
enum XML_Status XML_ResumeParser(XML_Parser parser)
Definition xmlparse.c:2270
XML_Parser XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, const XML_Char *namespaceSeparator)
Definition xmlparse.c:1058
#define XML_TRUE
Definition expat.h:58
int XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing)
Definition xmlparse.c:1895
XML_Status
Definition expat.h:74
XML_Parser XML_ExternalEntityParserCreate(XML_Parser parser, const XML_Char *context, const XML_Char *encoding)
Definition xmlparse.c:1354
XML_Expat_Version XML_ExpatVersionInfo(void)
Definition xmlparse.c:2556
#define XML_GE
char XML_Char
char XML_LChar
#define XMLCALL
unsigned long XML_Size
apr_text_header const char * text
Definition apr_xml.h:78
apr_xml_parser ** parser
Definition apr_xml.h:228
apr_size_t size
const char * input
Definition apr_cstr.h:93
void * data
apr_array_header_t ** result
const char * s
Definition apr_strings.h:95
const apr_array_header_t * first
Definition apr_tables.h:207
const apr_array_header_t const apr_array_header_t * second
Definition apr_tables.h:208
void XMLCALL accumulate_characters(void *userData, const XML_Char *s, int len)
Definition handlers.c:1910
int XMLCALL external_entity_failer__if_not_xml_ge(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId)
Definition handlers.c:675
void XMLCALL start_element_issue_240(void *userData, const XML_Char *name, const XML_Char **atts)
Definition handlers.c:260
void XMLCALL accumulate_start_element(void *userData, const XML_Char *name, const XML_Char **atts)
Definition handlers.c:1886
void XMLCALL accumulate_entity_decl(void *userData, const XML_Char *entityName, int is_parameter_entity, const XML_Char *value, int value_length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName)
Definition handlers.c:1864
void XMLCALL end_element_issue_240(void *userData, const XML_Char *name)
Definition handlers.c:269
#define UNUSED_P(p)
Definition internal.h:137
void * tracking_malloc(size_t size)
Definition memcheck.c:57
void * tracking_realloc(void *ptr, size_t size)
Definition memcheck.c:128
void tracking_free(void *ptr)
Definition memcheck.c:100
int tracking_report(void)
Definition memcheck.c:179
void tcase_add_test(TCase *tc, tcase_test_function test)
Definition minicheck.c:92
void suite_add_tcase(Suite *suite, TCase *tc)
Definition minicheck.c:74
void set_subtest(char const *fmt,...)
Definition minicheck.c:157
void tcase_add_checked_fixture(TCase *tc, tcase_setup_function setup, tcase_teardown_function teardown)
Definition minicheck.c:84
TCase * tcase_create(const char *name)
Definition minicheck.c:65
#define fail(msg)
Definition minicheck.h:87
#define END_TEST
Definition minicheck.h:81
#define assert_true(cond)
Definition minicheck.h:88
#define START_TEST(testname)
Definition minicheck.h:77
static int versions_equal(const XML_Expat_Version *first, const XML_Expat_Version *second)
Definition misc_tests.c:191
static void test_misc_attribute_leak(void)
Definition misc_tests.c:248
static void test_misc_alloc_create_parser(void)
Definition misc_tests.c:63
static void test_misc_tag_mismatch_reset_leak(void)
Definition misc_tests.c:393
static void test_misc_stop_during_end_handler_issue_240_1(void)
Definition misc_tests.c:288
static void test_misc_error_string(void)
Definition misc_tests.c:121
static void test_misc_stop_during_end_handler_issue_240_2(void)
Definition misc_tests.c:309
static void test_misc_stopparser_rejects_unstarted_parser(void)
Definition misc_tests.c:509
static int parse_version(const XML_LChar *version_text, XML_Expat_Version *version_struct)
Definition misc_tests.c:148
static void test_misc_create_external_entity_parser_with_null_context(void)
Definition misc_tests.c:417
void make_miscellaneous_test_case(Suite *s)
Definition misc_tests.c:523
static void XMLCALL resumable_stopping_character_handler(void *userData, const XML_Char *s, int len)
Definition misc_tests.c:479
static void test_misc_deny_internal_entity_closing_doctype_issue_317(void)
Definition misc_tests.c:330
static void test_misc_utf16le(void)
Definition misc_tests.c:265
static void test_misc_alloc_create_parser_with_encoding(void)
Definition misc_tests.c:83
static void test_misc_version(void)
Definition misc_tests.c:197
static void test_misc_char_handler_stop_without_leak(void)
Definition misc_tests.c:488
static void test_misc_features(void)
Definition misc_tests.c:217
static void test_misc_null_parser(void)
Definition misc_tests.c:105
static void test_misc_general_entities_support(void)
Definition misc_tests.c:434
static void test_misc_resumeparser_not_crashing(void)
Definition misc_tests.c:500
static const ap_slotmem_provider_t * storage
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347