From a67912a1164f93a95f48ad54dd98da7d3bd96b7f Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 20 Oct 2024 19:28:54 +0200 Subject: [PATCH 1/3] Ignore xmlDefaultExternalEntityLoader leaks At least on Windows with libxml2 2.11.9, calling the default entity loader leaks a couple of bytes. Since we cannot do anything about that, we ignore these leaks. --- ext/libxml/libxml.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index a72aad5038de0..998f8d2ad2cf3 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -721,7 +721,10 @@ static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, /* no custom user-land callback set up; delegate to original loader */ if (!ZEND_FCC_INITIALIZED(LIBXML(entity_loader_callback))) { - return _php_libxml_default_entity_loader(URL, ID, context); + ZEND_IGNORE_LEAKS_BEGIN(); + ret = _php_libxml_default_entity_loader(URL, ID, context); + ZEND_IGNORE_LEAKS_END(); + return ret; } if (ID != NULL) { From 1e44f49f1a2ac3bff4df1c49764839f45eaa91a3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 20 Oct 2024 19:42:49 +0200 Subject: [PATCH 2/3] Ignore `xmlRelaxNGParse()` memory leaks `xmlRelaxNGParse()` calls `xmlRelaxNGInitTypes()` and that allocates memory. libxml2 recommends to call `xmlCleanupParser()` to free this memory, but we don't call this function for reasons. --- ext/dom/document.c | 2 ++ ext/xmlreader/php_xmlreader.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/ext/dom/document.c b/ext/dom/document.c index ba5e7dab3d844..a690bb59be59a 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -2023,7 +2023,9 @@ static void dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int type (xmlRelaxNGValidityErrorFunc) php_libxml_error_handler, (xmlRelaxNGValidityWarningFunc) php_libxml_error_handler, parser); + ZEND_IGNORE_LEAKS_BEGIN(); sptr = xmlRelaxNGParse(parser); + ZEND_IGNORE_LEAKS_END(); xmlRelaxNGFreeParserCtxt(parser); PHP_LIBXML_RESTORE_GLOBALS(parse); if (!sptr) { diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index de19695baa51f..13f8661ae1f91 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -334,7 +334,10 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz (xmlRelaxNGValidityWarningFunc) warn_func, parser); } + ZEND_IGNORE_LEAKS_BEGIN(); sptr = xmlRelaxNGParse(parser); + ZEND_IGNORE_LEAKS_END(); + xmlRelaxNGFreeParserCtxt(parser); PHP_LIBXML_RESTORE_GLOBALS(parse); From 00e1b1c6c6711bc24d9cdda0f63c345c64ecb3e4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 20 Oct 2024 23:54:42 +0200 Subject: [PATCH 3/3] Ignore further libxml leaks; update ignore leak macros We cater to two more potentially leaking libxml functions. We also need to update the `ZEND_IGNORE_LEAKS_BEGIN|END()` macros, since we now have to cater to recursion, so we need to store the original value of `_crtDbgFlag` and reset it afterwards. --- Zend/zend_portability.h | 7 +++++-- ext/dom/document.c | 2 ++ ext/xmlreader/php_xmlreader.c | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index f4609428326c7..22bba1eaf4152 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -733,8 +733,11 @@ extern "C++" { #endif #if defined(ZEND_WIN32) && defined(_DEBUG) -# define ZEND_IGNORE_LEAKS_BEGIN() _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & ~_CRTDBG_ALLOC_MEM_DF) -# define ZEND_IGNORE_LEAKS_END() _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_ALLOC_MEM_DF) +# define ZEND_IGNORE_LEAKS_BEGIN() \ + int zend_crtDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); \ + _CrtSetDbgFlag(zend_crtDbgFlag & ~_CRTDBG_ALLOC_MEM_DF) +# define ZEND_IGNORE_LEAKS_END() \ + _CrtSetDbgFlag(zend_crtDbgFlag) #else # define ZEND_IGNORE_LEAKS_BEGIN() # define ZEND_IGNORE_LEAKS_END() diff --git a/ext/dom/document.c b/ext/dom/document.c index a690bb59be59a..e4571ab2e6a5f 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -1917,7 +1917,9 @@ static void dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type) (xmlSchemaValidityErrorFunc) php_libxml_error_handler, (xmlSchemaValidityWarningFunc) php_libxml_error_handler, parser); + ZEND_IGNORE_LEAKS_BEGIN(); sptr = xmlSchemaParse(parser); + ZEND_IGNORE_LEAKS_END(); xmlSchemaFreeParserCtxt(parser); PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt); if (!sptr) { diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index 13f8661ae1f91..e1e93797a74d5 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -337,7 +337,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz ZEND_IGNORE_LEAKS_BEGIN(); sptr = xmlRelaxNGParse(parser); ZEND_IGNORE_LEAKS_END(); - + xmlRelaxNGFreeParserCtxt(parser); PHP_LIBXML_RESTORE_GLOBALS(parse); @@ -1085,7 +1085,9 @@ PHP_METHOD(XMLReader, setSchema) intern = Z_XMLREADER_P(id); if (intern && intern->ptr) { PHP_LIBXML_SANITIZE_GLOBALS(schema); + ZEND_IGNORE_LEAKS_BEGIN(); retval = xmlTextReaderSchemaValidate(intern->ptr, source); + ZEND_IGNORE_LEAKS_END(); PHP_LIBXML_RESTORE_GLOBALS(schema); if (retval == 0) {