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);  } | 
