GNOME Bugzilla – Bug 777432
SEGV when extensions add text nodes with xmlAddChild
Last modified: 2017-02-10 13:19:27 UTC
Reproducable on different machines (debian-based) with version 1.1.28, 1.1.19 and git master.
+ Trace 237067
Reproducable with following minimal example: #include <string.h> #include <libintl.h> #include <libxslt/xslt.h> #include <libxslt/transform.h> #include <libxslt/xsltutils.h> #include <libxslt/extensions.h> #define UNUSED __attribute__((__unused__)) #define XSLT_MODUL_URI "http://test.uri" static void XsltGettext(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst, UNUSED xsltStylePreCompPtr comp) { xmlChar *text; if(ctxt == NULL||node==NULL||inst==NULL||ctxt->insert==NULL) { xsltGenericError(xsltGenericErrorContext, "error\n"); return; } text = BAD_CAST gettext("text"); node = xmlNewText(text); xmlAddChild(ctxt->insert, node); } static void* xsltInitFct(xsltTransformContextPtr ctxt, UNUSED const xmlChar *URI) { xsltRegisterExtElement(ctxt, (const xmlChar*)"gettext", (const xmlChar*)XSLT_MODUL_URI, (xsltTransformFunction)XsltGettext); return NULL; } static void xsltShutdownFct(UNUSED xsltTransformContextPtr ctxt, UNUSED const xmlChar *URI, UNUSED void *data) {} int main(UNUSED int argc, UNUSED char **argv) { xsltStylesheetPtr cur; const char *params[1] = {NULL}; xmlDocPtr xslDoc = NULL, xmlDoc = NULL, htmlDoc = NULL; const char *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\ <test>\ <sub><s>startdate starttime</s><e>enddate endtime</e></sub>\ </test>"; const char *xsl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\ <xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\" xmlns:test=\"http://test.uri\" extension-element-prefixes=\"test\">\ <xsl:template match=\"test\">\ <xsl:for-each select=\"sub\">\ <a><xsl:value-of select=\"position()\"/>. <test:gettext>sub</test:gettext> : <xsl:value-of select=\"s\"/><test:gettext> till </test:gettext><xsl:value-of select=\"e\"/></a>\ </xsl:for-each>\ </xsl:template>\ </xsl:stylesheet>"; xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; xsltRegisterExtModule((const xmlChar*)XSLT_MODUL_URI, xsltInitFct, xsltShutdownFct); xmlDoc = xmlReadMemory(xml, strlen(xml), "test", NULL, XML_PARSE_NOBLANKS); if(xmlDoc == NULL) return 1; xslDoc = xmlReadMemory(xsl, strlen(xsl), "stylesheet", NULL, XML_PARSE_NOBLANKS); if(xslDoc == NULL) return 1; cur = xsltParseStylesheetDoc(xslDoc); htmlDoc = xsltApplyStylesheet(cur, xmlDoc, params); unsigned char *buf = NULL; int len = 0; xmlDocDumpFormatMemory(htmlDoc, &buf, &len, 1); printf("%s\n", buf); xsltFreeStylesheet(cur); xmlFreeDoc(xmlDoc); xmlFreeDoc(htmlDoc); xsltCleanupGlobals(); xmlCleanupParser(); xmlMemoryDump(); return 0; }
libxslt uses an internal optimization when adding text to result elements that breaks if xmlAddChild is used. Extensions should use xsltCopyTextString instead: http://xmlsoft.org/XSLT/html/libxslt-transform.html#xsltCopyTextString This behavior is completely unexpected and libxslt really should allow to append text nodes with xmlAddChild, so I'm leaving this bug open.
(In reply to Nick Wellnhofer from comment #1) > libxslt uses an internal optimization when adding text to result elements > that breaks if xmlAddChild is used. Extensions should use xsltCopyTextString > instead: > > http://xmlsoft.org/XSLT/html/libxslt-transform.html#xsltCopyTextString > > This behavior is completely unexpected and libxslt really should allow to > append text nodes with xmlAddChild, so I'm leaving this bug open. Thanks a lot! Using xsltCopyTextString eliminate all problems. It would be useful to add that hint also on http://xmlsoft.org/XSLT/extensions.html#Example That page suggests to use AddChild for extensions.
Fixed with the following commit: https://git.gnome.org/browse/libxslt/commit/?id=ec547b2c12dc12e1277bc527fdc6b37a2feb1b43 Extensions can now append text with xmlAddChild safely. The xsltCopyTextString optimization is disabled for extension elements. I can't see how to make it work safely for code that might call xmlAddChild.