GNOME Bugzilla – Bug 168327
Segmentation fault when calling xsltFreeTransformContext() in multi-threaded program
Last modified: 2009-08-15 18:40:50 UTC
Steps to reproduce: Comiple the following C program (ctxt.c) using the following command (you may change the paths for the lib and include for your own environment): gcc -o ctxt ctxt.c -I/x/contrib/libxml2-2.6.17/include/libxml2 - L/x/contrib/libxml2-2.6.17/lib -lxml2 -I/x/contrib/libxslt-1.1.12/include - L/x/contrib/libxslt-1.1.12/lib -lxslt -g -lpthread Copy the attached xsl file (test.xsl) and xml file (test.xml) to the current directory, then do: ./ctxt test.xsl test.xml > /dev/null You will see a core dumped in a few seconds. I noticed the problem is mainly caused by the 'variable' declaration in test.xsl, if I remove that line, the program runs fine without a problem. So I think xsltFreeGlobalVariables() (called by xsltFreeTransformContext() in this case) is not thread safe. Source code for the C program (ctxt.c): /* * Testing xslt */ #include <stdio.h> #include <sys/time.h> #include <signal.h> #include <errno.h> #include <pthread.h> #include <sys/types.h> #include <libxml/SAX.h> #include <libxml/entities.h> #include <libxml/encoding.h> #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> #include <libxml/HTMLparser.h> #include <libxml/HTMLtree.h> #include <libxml/debugXML.h> #include <libxml/tree.h> #include <libxml/list.h> #include <libxml/hash.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> #include <libxml/xpointer.h> #include <libxml/xinclude.h> #include <libxml/xmlIO.h> #include <libxml/xmlmemory.h> #include <libxml/nanohttp.h> #include <libxml/nanoftp.h> #include <libxml/uri.h> #include <libxml/valid.h> #include <libxml/xlink.h> #include <libxml/xmlversion.h> #include <libxml/catalog.h> #include <libxml/threads.h> #include <libxml/globals.h> #include <libxml/c14n.h> #include <libxml/xmlautomata.h> #include <libxml/xmlregexp.h> #include <libxml/xmlschemas.h> #include <libxml/schemasInternals.h> #include <libxml/xmlschemastypes.h> #include <libxml/xmlunicode.h> #include <libxml/xmlreader.h> #include <libxml/relaxng.h> #include <libxml/SAX2.h> #include <libxml/xmlexports.h> #include <libxml/xmlwriter.h> #include <libxml/chvalid.h> #include <libxml/pattern.h> #include <libxslt/xslt.h> #include <libxslt/xsltutils.h> #include <libxslt/pattern.h> #include <libxslt/templates.h> #include <libxslt/variables.h> #include <libxslt/keys.h> #include <libxslt/numbersInternals.h> #include <libxslt/extensions.h> #include <libxslt/extra.h> #include <libxslt/functions.h> #include <libxslt/namespaces.h> #include <libxslt/imports.h> #include <libxslt/attributes.h> #include <libxslt/documents.h> #include <libxslt/preproc.h> #include <libxslt/transform.h> #include <libxslt/security.h> #include <libxslt/xsltInternals.h> #include <libxslt/xsltconfig.h> #include <libxslt/xsltexports.h> #include <libexslt/exsltconfig.h> #include <libexslt/exslt.h> void timeout(); xsltStylesheetPtr xsl_cur = NULL; char xml_file[100]; /* * the thread code that processes xslt requests */ void *generate_html(void *ns) { xmlDocPtr results_info; xsltTransformContextPtr ctxt; xmlDocPtr result = NULL; xmlChar * result_xmlchar; int result_len; int nbytes; results_info = xmlParseFile(xml_file); ctxt = xsltNewTransformContext(xsl_cur, results_info); result = xsltApplyStylesheetUser(xsl_cur, results_info, NULL, // style_params, NULL, // output NULL, // profile ctxt); // context nbytes = xsltSaveResultToString(&result_xmlchar, &result_len, result, xsl_cur); printf("result: %s\n", result_xmlchar); xmlFreeDoc(result); xmlFreeDoc(results_info); xmlFree(result_xmlchar); xsltFreeTransformContext(ctxt); pthread_exit(NULL); } main(int argc, char *argv[]) { pthread_t t; int rc; int i, j; xmlDocPtr xsl_style = NULL; xmlGlobalState gs; xmlInitializeGlobalState(&gs); if (argc < 3) { fprintf(stderr, "Usage: ctxt xsl_file xml_file\n"); exit(1); } printf("version=%s\n", LIBXSLT_DOTTED_VERSION); printf("version=%s\n", LIBXML_DOTTED_VERSION); strcpy(xml_file, argv[2]); xsl_style = xmlReadFile(argv[1], NULL, XSLT_PARSE_OPTIONS); if (xsl_style == NULL) { printf("ERROR: read xsl file: %s\n", argv[1]); exit(1); } xsl_cur = xsltParseStylesheetDoc(xsl_style); if (xsl_cur == NULL) { printf("ERROR: load xsl file: %s\n", argv[1]); } while (1) { sleep(1); for (j = 0; j < 10; j++) { rc = pthread_create(&t, NULL, generate_html, (void *)0); if (rc){ printf("ERROR; return code from pthread_create() is % d\n", rc); exit(-1); } pthread_detach(t); } } } test.xsl <?xml version="1.0"?><xst:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xst="http://www.w3.org/1999/XSL/Transform"> <xst:output indent="yes" method="html" /> <xst:strip-space elements="*" /> <xst:variable name="PPRD" select="/ResultDoc" /> <xst:template match="/ResultDoc"> <html> </html> </xst:template> </xst:stylesheet> test.xml: <ResultDoc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Properties> <Length>1000</Length> </Properties> </ResultDoc> Stack trace:
+ Trace 56057
Other information: I am running it on Linux
This problem is nothing to do with threads, but rather is an error in your coding. Within the routine "generate_html", at the end, you have code to free the resources. This, of course, is a proper thing to do. However, care must be taken to assure the resources are freed in the proper order. The parsed xml document "results_info" is used by the xslt transformation context, so when you free that document before freeing the context which is using it, the crash occurs. A good general rule to follow is to always free the resources in the reverse order from which they were related. When I made that change, and also reduced the sleep time down to 50 milliseconds, on my reasonably-fast dual-Athlon system there was no problem (ran for about 1/2 hour). One other unrelated point - although it is certainly not an error, when you have a #include for almost every possible libxml2 and libxslt include file, it makes the program a bit difficult to digest :-). For this particular example program, only three includes are really needed - #include <libxml/parser.h> /* for libxml2 parsing */ #include <libxslt/transform.h> /* for libxslt transformations */ #include <libxslt/xsltutils.h> /* for XSLT_DOTTED_VERSION */ Hope that's helpful - Bill
I changed the order or free's in my original code, it worked. Thanks for the quick response.