From c1420fcf7d9e899b3378e25f5e21776f6461b4a4 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 26 Jul 2011 16:29:53 -0400
Subject: [PATCH] Check to see whether libxml2 handles error context the way we
 expect.

It turns out to be possible to link against a libxml2.so that does this
differently than the version we configured and built against, so we need
a runtime check to avoid bizarre behavior.  Per report from Bernd Helmle.
Patch by Florian Pflug.
---
 src/backend/utils/adt/xml.c | 38 +++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index f3db3f07548..99b978c42c0 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -928,6 +928,7 @@ PgXmlErrorContext *
 pg_xml_init(PgXmlStrictness strictness)
 {
 	PgXmlErrorContext *errcxt;
+	void	   *new_errcxt;
 
 	/* Do one-time setup if needed */
 	pg_xml_init_library();
@@ -956,6 +957,34 @@ pg_xml_init(PgXmlStrictness strictness)
 
 	xmlSetStructuredErrorFunc((void *) errcxt, xml_errorHandler);
 
+	/*
+	 * Verify that xmlSetStructuredErrorFunc set the context variable we
+	 * expected it to.  If not, the error context pointer we just saved is not
+	 * the correct thing to restore, and since that leaves us without a way to
+	 * restore the context in pg_xml_done, we must fail.
+	 *
+	 * The only known situation in which this test fails is if we compile with
+	 * headers from a libxml2 that doesn't track the structured error context
+	 * separately (<= 2.7.3), but at runtime use a version that does, or vice
+	 * versa.  The libxml2 authors did not treat that change as constituting
+	 * an ABI break, so the LIBXML_TEST_VERSION test in pg_xml_init_library
+	 * fails to protect us from this.
+	 */
+
+#ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
+	new_errcxt = xmlStructuredErrorContext;
+#else
+	new_errcxt = xmlGenericErrorContext;
+#endif
+
+	if (new_errcxt != (void *) errcxt)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("could not set up XML error handler"),
+				 errhint("This probably indicates that the version of libxml2"
+						 " being used is not compatible with the libxml2"
+						 " header files that PostgreSQL was built with.")));
+
 	return errcxt;
 }
 
@@ -1494,9 +1523,14 @@ xml_errorHandler(void *data, xmlErrorPtr error)
 	int			level = error->level;
 	StringInfo	errorBuf;
 
-	/* Defend against someone passing us a bogus context struct */
+	/*
+	 * Defend against someone passing us a bogus context struct.
+	 *
+	 * We force a backend exit if this check fails because longjmp'ing out of
+	 * libxml would likely render it unsafe to use further.
+	 */
 	if (xmlerrcxt->magic != ERRCXT_MAGIC)
-		elog(ERROR, "xml_errorHandler called with invalid PgXmlErrorContext");
+		elog(FATAL, "xml_errorHandler called with invalid PgXmlErrorContext");
 
 	/*----------
 	 * Older libxml versions report some errors differently.
-- 
GitLab