From bc8fbe2683b1dd918fdcbfa120d57d06b4329aaa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 23 Jun 2025 11:50:47 +0100 Subject: [PATCH] util: workaround libxml2 lack of thread safe initialization MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The main XML parser code global initializer historically had a mutex protecting it, and more recently uses a pthread_once. The RelaxNG code, however, relies on two other global initializers that are not thread safe, just relying on setting an integer "initialized" flag. Calling the relevant initializers from libvirt in a protected global initializer will protect libvirt's own concurrent usage, however, it cannot protect against other libraries loaded in process that might be using libxml2's schema code. Fortunately: * The chances of other loaded non-libvirt code using libxml is relatively low * The chances of other loaded non-libvirt code using the schema validation / catalog functionality inside libxml is even lower * The chances of both libvirt and the non-libvirt usage having their *1st* usage of libxml2 be concurrent is tiny IOW, in practice, although our solution doesn't fully fix the thread safety, it is good enough. libxml2 should none the less still be fixed to make its global initializers be thread safe without special actions by its API consumers[1]. Resolves: https://gitlab.com/libvirt/libvirt/-/issues/788 [1] https://gitlab.gnome.org/GNOME/libxml2/-/merge_requests/326 Reviewed-by: Peter Krempa Signed-off-by: Daniel P. Berrangé --- src/util/virxml.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/util/virxml.c b/src/util/virxml.c index 9d46e5f32f..bb80bb7444 100644 --- a/src/util/virxml.c +++ b/src/util/virxml.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include "virerror.h" #include "virxml.h" @@ -35,6 +37,7 @@ #include "virstring.h" #include "virutil.h" #include "viruuid.h" +#include "virthread.h" #include "configmake.h" #define VIR_FROM_THIS VIR_FROM_XML @@ -50,6 +53,28 @@ struct virParserData { }; +static int +virXMLSchemaOnceInit(void) +{ +#if LIBXML_VERSION >= 21100 + if (xmlSchemaInitTypes() < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to initialize libxml2 schema types")); + return -1; + } +#else + xmlSchemaInitTypes(); +#endif + if (xmlRelaxNGInitTypes() < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to initialize libxml2 RelaxNG data")); + return -1; + } + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virXMLSchema); + static xmlXPathContextPtr virXMLXPathContextNew(xmlDocPtr xml) { @@ -1603,6 +1628,9 @@ virXMLValidatorInit(const char *schemafile) { g_autoptr(virXMLValidator) validator = NULL; + if (virXMLSchemaInitialize() < 0) + return NULL; + validator = g_new0(virXMLValidator, 1); validator->schemafile = g_strdup(schemafile); -- 2.39.5