CDATA text nodes can cause ctxt->lasttsize to be incorrect, bug?

Noam Postavsky <[email protected]>
Newsgroups gmane.comp.gnome.lib.xslt
Message-ID <[email protected]>
xsltAddTextString (transform.c:708) allocates some extra space to
target->content in order to avoid future allocations. If a CDATA node is
added after this, the node gets added by xmlAddChild() which will merge
the text and realloc() the content which means the extra space is no
longer available. The problem is that ctxt->lasttsize still reflects the
extra space allocation so a subsequent text node may corrupt memory.
I've attached a small program to show the problem.

Now this isn't a problem if XML_PARSE_NOCDATA is used because there
won't be any CDATA nodes. So is it expected behaviour that libxslt fails
when given a stylesheet with CDATA nodes, or is this a bug?

thanks, Noam

_______________________________________________
xslt mailing list, project page http://xmlsoft.org/XSLT/
[email protected]
http://mail.gnome.org/mailman/listinfo/xslt
xslt-crash.c (application/octet-stream, 2.8 KB)
/*
 * adapted from libxslt_tutorial.c:
 * http://xmlsoft.org/xslt/tutorial/libxslttutorial.html
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxslt/xslt.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>

static const int MAGIC = 0x12345678;

typedef struct {
    size_t size;
    int magic;
} memheader;
typedef struct {
    int magic;
    size_t size;
} memfooter;

void* get_mem(memheader *header) {
    return ((void*)header) + sizeof(memheader);
}
memheader* get_memheader(void *mem) {
    return mem - sizeof(memheader);
}
memfooter* get_memfooter(memheader *header) {
    return ((void*) header) + sizeof(memheader) + header->size;
}
void check_head_foot(void *mem) {
    memheader *header = get_memheader(mem);
    memfooter *footer = get_memfooter(header);
    assert(header->magic == MAGIC);
    assert(footer->magic == MAGIC);
    assert(header->size == footer->size);
}

void checked_free(void *mem) {
    if (!mem) return;
    check_head_foot(mem);
    free(get_memheader(mem));
}
void* checked_malloc(size_t size) {
    memfooter *footer;
    memheader *header = malloc(size + sizeof(memheader) + sizeof(memfooter));
    header->magic = MAGIC;
    header->size = size;
    footer = get_memfooter(header);
    footer->magic = MAGIC;
    footer->size = size;
    return get_mem(header);
}
void* checked_realloc(void *mem, size_t size) {
    memfooter *footer;
    memheader *header;
    if (mem) check_head_foot(mem);
    header = realloc(mem? get_memheader(mem) : NULL, size + sizeof(memheader) + sizeof(memfooter));
    header->magic = MAGIC;
    header->size = size;
    footer = get_memfooter(header);
    footer->magic = MAGIC;
    footer->size = size;
    return get_mem(header);
}
char* checked_strdup(const char *str) {
    int len = strlen(str);
    char *newstr = checked_malloc(len+1);
    memcpy(newstr, str, len);
    newstr[len] = '\0';
    return newstr;
}

extern int xmlLoadExtDtdDefaultValue;

static void usage(const char *name) {
    printf("Usage: %s stylesheet <xsl-file> <xml-file>\n", name);
}

int
main(int argc, char **argv) {
    int i = 1;
    xsltStylesheetPtr cur;
    xmlDocPtr doc, res, style_doc;

    if (argc <= 1) {
        usage(argv[0]);
        return(1);
    }

    xmlInitMemory();
    xmlMemSetup(checked_free, checked_malloc, checked_realloc, checked_strdup);

    xmlSubstituteEntitiesDefault(1);
    xmlLoadExtDtdDefaultValue = 1;
    /* passing XML_PARSE_NOCDATA avoid crash */
    style_doc = xmlReadFile(argv[i], NULL, 0);
    cur = xsltParseStylesheetDoc(style_doc);
    i++;
    doc = xmlParseFile(argv[i]);
    res = xsltApplyStylesheet(cur, doc, NULL);
    xsltSaveResultToFile(stdout, res, cur);

    xsltFreeStylesheet(cur);
    xmlFreeDoc(res);
    xmlFreeDoc(doc);

    xsltCleanupGlobals();
    xmlCleanupParser();
    return(0);
}
crash.xsl (application/octet-stream, 348 B) - not displayed
crash.xml (text/pl, 45 B)
<?xml version="1.0" encoding="UTF-8" ?>
<x/>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.