diff options
Diffstat (limited to 'contrib/expat/tests/alloc_tests.c')
-rw-r--r-- | contrib/expat/tests/alloc_tests.c | 242 |
1 files changed, 239 insertions, 3 deletions
diff --git a/contrib/expat/tests/alloc_tests.c b/contrib/expat/tests/alloc_tests.c index 12ea3b2a81d2..5ae6c6a72025 100644 --- a/contrib/expat/tests/alloc_tests.c +++ b/contrib/expat/tests/alloc_tests.c @@ -10,7 +10,7 @@ Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net> Copyright (c) 2005-2007 Steven Solie <steven@solie.ca> Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net> - Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org> + Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org> Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk> Copyright (c) 2017 Joe Orton <jorton@redhat.com> Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com> @@ -46,10 +46,16 @@ # undef NDEBUG /* because test suite relies on assert(...) at the moment */ #endif +#include <math.h> /* NAN, INFINITY */ +#include <stdbool.h> +#include <stdint.h> /* for SIZE_MAX */ #include <string.h> #include <assert.h> +#include "expat_config.h" + #include "expat.h" +#include "internal.h" #include "common.h" #include "minicheck.h" #include "dummy.h" @@ -323,7 +329,7 @@ START_TEST(test_alloc_run_external_parser) { XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); XML_SetUserData(g_parser, foo_text); XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader); - g_allocation_count = i; + g_allocation_count = (int)i; if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_ERROR) break; @@ -434,7 +440,7 @@ START_TEST(test_alloc_internal_entity) { const unsigned int max_alloc_count = 20; for (i = 0; i < max_alloc_count; i++) { - g_allocation_count = i; + g_allocation_count = (int)i; XML_SetUnknownEncodingHandler(g_parser, unknown_released_encoding_handler, NULL); if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) @@ -2085,6 +2091,226 @@ START_TEST(test_alloc_reset_after_external_entity_parser_create_fail) { } END_TEST +#if XML_GE == 1 +static size_t +sizeRecordedFor(void *ptr) { + return *(size_t *)((char *)ptr - EXPAT_MALLOC_PADDING - sizeof(size_t)); +} +#endif // XML_GE == 1 + +START_TEST(test_alloc_tracker_size_recorded) { + XML_Memory_Handling_Suite memsuite = {malloc, realloc, free}; + + bool values[] = {true, false}; + for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) { + const bool useMemSuite = values[i]; + set_subtest("useMemSuite=%d", (int)useMemSuite); + XML_Parser parser = useMemSuite + ? XML_ParserCreate_MM(NULL, &memsuite, XCS("|")) + : XML_ParserCreate(NULL); + +#if XML_GE == 1 + void *ptr = expat_malloc(parser, 10, -1); + + assert_true(ptr != NULL); + assert_true(sizeRecordedFor(ptr) == 10); + + assert_true(expat_realloc(parser, ptr, SIZE_MAX / 2, -1) == NULL); + + assert_true(sizeRecordedFor(ptr) == 10); // i.e. unchanged + + ptr = expat_realloc(parser, ptr, 20, -1); + + assert_true(ptr != NULL); + assert_true(sizeRecordedFor(ptr) == 20); + + expat_free(parser, ptr, -1); +#endif + + XML_ParserFree(parser); + } +} +END_TEST + +START_TEST(test_alloc_tracker_pointer_alignment) { + XML_Parser parser = XML_ParserCreate(NULL); +#if XML_GE == 1 + assert_true(sizeof(long long) >= sizeof(size_t)); // self-test + long long *const ptr + = (long long *)expat_malloc(parser, 4 * sizeof(long long), -1); + ptr[0] = 0LL; + ptr[1] = 1LL; + ptr[2] = 2LL; + ptr[3] = 3LL; + expat_free(parser, ptr, -1); +#endif + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_alloc_tracker_maximum_amplification) { + if (g_reparseDeferralEnabledDefault == XML_TRUE) { + return; + } + + XML_Parser parser = XML_ParserCreate(NULL); + + // Get .m_accounting.countBytesDirect from 0 to 3 + const char *const chunk = "<e>"; + assert_true(_XML_Parse_SINGLE_BYTES(parser, chunk, (int)strlen(chunk), + /*isFinal=*/XML_FALSE) + == XML_STATUS_OK); + +#if XML_GE == 1 + // Stop activation threshold from interfering + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); + + // Exceed maximum amplification: should be rejected. + assert_true(expat_malloc(parser, 1000, -1) == NULL); + + // Increase maximum amplification, and try the same amount once more: should + // work. + assert_true(XML_SetAllocTrackerMaximumAmplification(parser, 3000.0f) + == XML_TRUE); + + void *const ptr = expat_malloc(parser, 1000, -1); + assert_true(ptr != NULL); + expat_free(parser, ptr, -1); +#endif + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_alloc_tracker_threshold) { + XML_Parser parser = XML_ParserCreate(NULL); + +#if XML_GE == 1 + // Exceed maximum amplification *before* (default) threshold: should work. + void *const ptr = expat_malloc(parser, 1000, -1); + assert_true(ptr != NULL); + expat_free(parser, ptr, -1); + + // Exceed maximum amplification *after* threshold: should be rejected. + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 999) == XML_TRUE); + assert_true(expat_malloc(parser, 1000, -1) == NULL); +#endif + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_alloc_tracker_getbuffer_unlimited) { + XML_Parser parser = XML_ParserCreate(NULL); + +#if XML_GE == 1 + // Artificially lower threshold + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); + + // Self-test: Prove that threshold is as rejecting as expected + assert_true(expat_malloc(parser, 1000, -1) == NULL); +#endif + // XML_GetBuffer should be allowed to pass, though + assert_true(XML_GetBuffer(parser, 1000) != NULL); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_alloc_tracker_api) { + XML_Parser parserWithoutParent = XML_ParserCreate(NULL); + XML_Parser parserWithParent = XML_ExternalEntityParserCreate( + parserWithoutParent, XCS("entity123"), NULL); + if (parserWithoutParent == NULL) + fail("parserWithoutParent is NULL"); + if (parserWithParent == NULL) + fail("parserWithParent is NULL"); + +#if XML_GE == 1 + // XML_SetAllocTrackerMaximumAmplification, error cases + if (XML_SetAllocTrackerMaximumAmplification(NULL, 123.0f) == XML_TRUE) + fail("Call with NULL parser is NOT supposed to succeed"); + if (XML_SetAllocTrackerMaximumAmplification(parserWithParent, 123.0f) + == XML_TRUE) + fail("Call with non-root parser is NOT supposed to succeed"); + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, NAN) + == XML_TRUE) + fail("Call with NaN limit is NOT supposed to succeed"); + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, -1.0f) + == XML_TRUE) + fail("Call with negative limit is NOT supposed to succeed"); + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 0.9f) + == XML_TRUE) + fail("Call with positive limit <1.0 is NOT supposed to succeed"); + + // XML_SetAllocTrackerMaximumAmplification, success cases + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 1.0f) + == XML_FALSE) + fail("Call with positive limit >=1.0 is supposed to succeed"); + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, 123456.789f) + == XML_FALSE) + fail("Call with positive limit >=1.0 is supposed to succeed"); + if (XML_SetAllocTrackerMaximumAmplification(parserWithoutParent, INFINITY) + == XML_FALSE) + fail("Call with positive limit >=1.0 is supposed to succeed"); + + // XML_SetAllocTrackerActivationThreshold, error cases + if (XML_SetAllocTrackerActivationThreshold(NULL, 123) == XML_TRUE) + fail("Call with NULL parser is NOT supposed to succeed"); + if (XML_SetAllocTrackerActivationThreshold(parserWithParent, 123) == XML_TRUE) + fail("Call with non-root parser is NOT supposed to succeed"); + + // XML_SetAllocTrackerActivationThreshold, success cases + if (XML_SetAllocTrackerActivationThreshold(parserWithoutParent, 123) + == XML_FALSE) + fail("Call with non-NULL parentless parser is supposed to succeed"); +#endif // XML_GE == 1 + + XML_ParserFree(parserWithParent); + XML_ParserFree(parserWithoutParent); +} +END_TEST + +START_TEST(test_mem_api_cycle) { + XML_Parser parser = XML_ParserCreate(NULL); + + void *ptr = XML_MemMalloc(parser, 10); + + assert_true(ptr != NULL); + memset(ptr, 'x', 10); // assert writability, with ASan in mind + + ptr = XML_MemRealloc(parser, ptr, 20); + + assert_true(ptr != NULL); + memset(ptr, 'y', 20); // assert writability, with ASan in mind + + XML_MemFree(parser, ptr); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_mem_api_unlimited) { + XML_Parser parser = XML_ParserCreate(NULL); + +#if XML_GE == 1 + assert_true(XML_SetAllocTrackerActivationThreshold(parser, 0) == XML_TRUE); +#endif + + void *ptr = XML_MemMalloc(parser, 1000); + + assert_true(ptr != NULL); + + ptr = XML_MemRealloc(parser, ptr, 2000); + + assert_true(ptr != NULL); + + XML_MemFree(parser, ptr); + + XML_ParserFree(parser); +} +END_TEST + void make_alloc_test_case(Suite *s) { TCase *tc_alloc = tcase_create("allocation tests"); @@ -2151,4 +2377,14 @@ make_alloc_test_case(Suite *s) { tcase_add_test__ifdef_xml_dtd( tc_alloc, test_alloc_reset_after_external_entity_parser_create_fail); + + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_size_recorded); + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_pointer_alignment); + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_maximum_amplification); + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_threshold); + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_getbuffer_unlimited); + tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api); + + tcase_add_test(tc_alloc, test_mem_api_cycle); + tcase_add_test__if_xml_ge(tc_alloc, test_mem_api_unlimited); } |