From f8399e62a31095bf1ced01827c33f9b29494046f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Fri, 19 Dec 2025 12:27:54 +0100 Subject: [PATCH 1/2] testcatalog: Add new tests for catalog.c Adds a new test program to run specific tests related to catalog parsing. This initial version includes a couple of tests, the first one to check the infinite recursion detection related to: https://gitlab.gnome.org/GNOME/libxml2/-/issues/1018. The second one tests the nextCatalog element repeated parsing, related to: https://gitlab.gnome.org/GNOME/libxml2/-/issues/1019 https://gitlab.gnome.org/GNOME/libxml2/-/issues/1040 --- CMakeLists.txt | 2 + Makefile.am | 6 ++ catalog.c | 63 +++++++++++----- include/libxml/catalog.h | 2 + meson.build | 1 + test/catalogs/catalog-recursive.xml | 3 + test/catalogs/repeated-next-catalog.xml | 10 +++ testcatalog.c | 96 +++++++++++++++++++++++++ 8 files changed, 164 insertions(+), 19 deletions(-) create mode 100644 test/catalogs/catalog-recursive.xml create mode 100644 test/catalogs/repeated-next-catalog.xml create mode 100644 testcatalog.c Index: libxml2-2.14.5/CMakeLists.txt =================================================================== --- libxml2-2.14.5.orig/CMakeLists.txt +++ libxml2-2.14.5/CMakeLists.txt @@ -488,6 +488,7 @@ if(LIBXML2_WITH_TESTS) runxmlconf runsuite testapi + testcatalog testchar testdict testModule @@ -512,6 +513,7 @@ if(LIBXML2_WITH_TESTS) if(NOT WIN32) add_test(NAME testapi COMMAND testapi) endif() + add_test(NAME testcatalog COMMAND testcatalog) add_test(NAME testchar COMMAND testchar) add_test(NAME testdict COMMAND testdict) add_test(NAME testparser COMMAND testparser WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) Index: libxml2-2.14.5/Makefile.am =================================================================== --- libxml2-2.14.5.orig/Makefile.am +++ libxml2-2.14.5/Makefile.am @@ -20,6 +20,7 @@ check_PROGRAMS = \ runxmlconf \ testModule \ testapi \ + testcatalog \ testchar \ testdict \ testlimits \ @@ -120,6 +121,10 @@ testlimits_SOURCES=testlimits.c testlimits_DEPENDENCIES = $(DEPS) testlimits_LDADD= $(LDADDS) +testcatalog_SOURCES=testcatalog.c +testcatalog_DEPENDENCIES = $(DEPS) +testcatalog_LDADD= $(LDADDS) + testchar_SOURCES=testchar.c testchar_DEPENDENCIES = $(DEPS) testchar_LDADD= $(LDADDS) @@ -169,6 +174,7 @@ check-local: $(CHECKER) ./runtest$(EXEEXT) $(CHECKER) ./testrecurse$(EXEEXT) $(CHECKER) ./testapi$(EXEEXT) + $(CHECKER) ./testcatalog$(EXEEXT) $(CHECKER) ./testchar$(EXEEXT) $(CHECKER) ./testdict$(EXEEXT) $(CHECKER) ./testparser$(EXEEXT) Index: libxml2-2.14.5/catalog.c =================================================================== --- libxml2-2.14.5.orig/catalog.c +++ libxml2-2.14.5/catalog.c @@ -637,43 +637,54 @@ static void xmlDumpXMLCatalogNode(xmlCat } } -static int -xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { - int ret; - xmlDocPtr doc; +static xmlDocPtr +xmlDumpXMLCatalogToDoc(xmlCatalogEntryPtr catal) { xmlNsPtr ns; xmlDtdPtr dtd; xmlNodePtr catalog; - xmlOutputBufferPtr buf; + xmlDocPtr doc = xmlNewDoc(NULL); + if (doc == NULL) { + return(NULL); + } - /* - * Rebuild a catalog - */ - doc = xmlNewDoc(NULL); - if (doc == NULL) - return(-1); dtd = xmlNewDtd(doc, BAD_CAST "catalog", - BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", -BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); + BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", + BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL); if (ns == NULL) { - xmlFreeDoc(doc); - return(-1); + xmlFreeDoc(doc); + return(NULL); } catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL); if (catalog == NULL) { - xmlFreeNs(ns); - xmlFreeDoc(doc); - return(-1); + xmlFreeDoc(doc); + xmlFreeNs(ns); + return(NULL); } catalog->nsDef = ns; xmlAddChild((xmlNodePtr) doc, catalog); - xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL); + return(doc); +} + +static int +xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { + int ret; + xmlDocPtr doc; + xmlOutputBufferPtr buf; + + /* + * Rebuild a catalog + */ + doc = xmlDumpXMLCatalogToDoc(catal); + if (doc == NULL) { + return(-1); + } + /* * reserialize it */ @@ -1236,7 +1247,6 @@ xmlParseXMLCatalogNode(xmlNodePtr cur, x while (prev != NULL) { if ((prev->type == XML_CATA_NEXT_CATALOG) && (xmlStrEqual (prev->URL, entry->URL)) && - (xmlStrEqual (prev->value, entry->value)) && (prev->prefer == entry->prefer) && (prev->group == entry->group)) { if (xmlDebugCatalogs) @@ -3369,6 +3379,20 @@ xmlCatalogDump(FILE *out) { xmlACatalogDump(xmlDefaultCatalog, out); } + +/** + * Dump all the global catalog content as a xmlDoc + * This function is just for testing/debugging purposes + * + * @returns The catalog as xmlDoc or NULL if failed, it must be freed by the caller. + */ +xmlDocPtr +xmlCatalogDumpDoc(void) { + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + return xmlDumpXMLCatalogToDoc(xmlDefaultCatalog->xml); +} #endif /* LIBXML_OUTPUT_ENABLED */ /** Index: libxml2-2.14.5/include/libxml/catalog.h =================================================================== --- libxml2-2.14.5.orig/include/libxml/catalog.h +++ libxml2-2.14.5/include/libxml/catalog.h @@ -119,6 +119,8 @@ XMLPUBFUN void #ifdef LIBXML_OUTPUT_ENABLED XMLPUBFUN void xmlCatalogDump (FILE *out); +XMLPUBFUN xmlDocPtr + xmlCatalogDumpDoc (void); #endif /* LIBXML_OUTPUT_ENABLED */ XMLPUBFUN xmlChar * xmlCatalogResolve (const xmlChar *pubID, Index: libxml2-2.14.5/meson.build =================================================================== --- libxml2-2.14.5.orig/meson.build +++ libxml2-2.14.5/meson.build @@ -539,6 +539,7 @@ checks = { # Disabled for now, see #694 # 'testModule': [], 'testapi': [], + 'testcatalog': [], 'testchar': [], 'testdict': [], 'testlimits': [], Index: libxml2-2.14.5/test/catalogs/catalog-recursive.xml =================================================================== --- /dev/null +++ libxml2-2.14.5/test/catalogs/catalog-recursive.xml @@ -0,0 +1,3 @@ + + + Index: libxml2-2.14.5/test/catalogs/repeated-next-catalog.xml =================================================================== --- /dev/null +++ libxml2-2.14.5/test/catalogs/repeated-next-catalog.xml @@ -0,0 +1,10 @@ + + + + + + + + + + Index: libxml2-2.14.5/testcatalog.c =================================================================== --- /dev/null +++ libxml2-2.14.5/testcatalog.c @@ -0,0 +1,96 @@ +/* + * testcatalog.c: C program to run libxml2 catalog.c unit tests + * + * To compile on Unixes: + * cc -o testcatalog `xml2-config --cflags` testcatalog.c `xml2-config --libs` -lpthread + * + * See Copyright for the status of this software. + * + * Author: Daniel Garcia + */ + + +#include "libxml.h" +#include + +#ifdef LIBXML_CATALOG_ENABLED +#include + +/* Test catalog resolve uri with recursive catalog */ +static int +testRecursiveDelegateUri(void) { + int ret = 0; + const char *cat = "test/catalogs/catalog-recursive.xml"; + const char *entity = "/foo.ent"; + xmlChar *resolved = NULL; + + xmlInitParser(); + xmlLoadCatalog(cat); + + /* This should trigger recursive error */ + resolved = xmlCatalogResolveURI(BAD_CAST entity); + if (resolved != NULL) { + fprintf(stderr, "CATALOG-FAILURE: Catalog %s entity should fail to resolve\n", entity); + ret = 1; + } + xmlCatalogCleanup(); + + return ret; +} + +/* Test parsing repeated NextCatalog */ +static int +testRepeatedNextCatalog(void) { + int ret = 0; + int i = 0; + const char *cat = "test/catalogs/repeated-next-catalog.xml"; + const char *entity = "/foo.ent"; + xmlDocPtr doc = NULL; + xmlNodePtr node = NULL; + + xmlInitParser(); + + xmlLoadCatalog(cat); + /* To force the complete recursive load */ + xmlCatalogResolveURI(BAD_CAST entity); + /** + * Ensure that the doc doesn't contain the same nextCatalog + */ + doc = xmlCatalogDumpDoc(); + xmlCatalogCleanup(); + + if (doc == NULL) { + fprintf(stderr, "CATALOG-FAILURE: Failed to dump the catalog\n"); + return 1; + } + + /* Just the root "catalog" node with a series of nextCatalog */ + node = xmlDocGetRootElement(doc); + node = node->children; + for (i=0; node != NULL; node=node->next, i++) {} + if (i > 1) { + fprintf(stderr, "CATALOG-FAILURE: Found %d nextCatalog entries and should be 1\n", i); + ret = 1; + } + + xmlFreeDoc(doc); + + return ret; +} + +int +main(void) { + int err = 0; + + err |= testRecursiveDelegateUri(); + err |= testRepeatedNextCatalog(); + + return err; +} +#else +/* No catalog, so everything okay */ +int +main(void) { + return 0; +} +#endif Index: libxml2-2.14.5/configure.ac =================================================================== --- libxml2-2.14.5.orig/configure.ac +++ libxml2-2.14.5/configure.ac @@ -41,7 +41,7 @@ AC_SUBST(LIBXML_VERSION_INFO) AC_SUBST(LIBXML_VERSION_NUMBER) AC_SUBST(LIBXML_VERSION_EXTRA) -AM_INIT_AUTOMAKE([1.16.3 foreign subdir-objects no-dist-gzip dist-xz]) +AM_INIT_AUTOMAKE([1.15.1 foreign subdir-objects no-dist-gzip dist-xz]) AM_MAINTAINER_MODE([enable]) AM_SILENT_RULES([yes])