Check to see whether libxml2 handles error context the way we expect.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 26 Jul 2011 20:29:53 +0000 (16:29 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 26 Jul 2011 20:31:04 +0000 (16:31 -0400)
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

index f3db3f075481e8e1872d0ae13759ca7b9a8b2135..99b978c42c08089f3675f6e675f419b2c935a3ae 100644 (file)
@@ -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.