1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-26 12:25:09 +03:00

integrated the Out Of Memory test from Havoc Pennington #109368 a lot of

* Makefile.am testOOM.c testOOMlib.[ch] : integrated the Out Of
  Memory test from Havoc Pennington #109368
* SAX.c parser.c parserInternals.c tree.c uri.c valid.c
  xmlmemory.c xmlreader.c xmlregexp.c include/libxml/tree.h
  include/libxml/parser.h: a lot of memory allocation cleanups
  based on the results of the OOM testing
* check-relaxng-test-suite2.py: seems I forgot to commit the
  script.
Daniel
This commit is contained in:
Daniel Veillard 2003-04-24 16:06:47 +00:00
parent 18f113da8c
commit a76fe5ca11
17 changed files with 1289 additions and 95 deletions

View File

@ -1,3 +1,14 @@
Thu Apr 24 18:01:46 CEST 2003 Daniel Veillard <daniel@veillard.com>
* Makefile.am testOOM.c testOOMlib.[ch] : integrated the Out Of
Memory test from Havoc Pennington #109368
* SAX.c parser.c parserInternals.c tree.c uri.c valid.c
xmlmemory.c xmlreader.c xmlregexp.c include/libxml/tree.h
include/libxml/parser.h: a lot of memory allocation cleanups
based on the results of the OOM testing
* check-relaxng-test-suite2.py: seems I forgot to commit the
script.
Wed Apr 23 17:16:41 CEST 2003 Daniel Veillard <daniel@veillard.com>
* xmlschemastypes.c: trivial fix for 109774 removing a warning

View File

@ -116,6 +116,11 @@ testReader_LDFLAGS =
testReader_DEPENDENCIES = $(DEPS)
testReader_LDADD= $(LDADDS)
testOOM_SOURCES=testOOM.c testOOMlib.h testOOMlib.c
testOOM_LDFLAGS =
testOOM_DEPENDENCIES = $(DEPS)
testOOM_LDADD= $(LDADDS)
check-local: tests
testall : tests SVGtests SAXtests

106
SAX.c
View File

@ -232,6 +232,8 @@ externalSubset(void *ctx, const xmlChar *name,
ctxt->sax->error(ctxt->userData,
"externalSubset: out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
ctxt->input = oldinput;
ctxt->inputNr = oldinputNr;
ctxt->inputMax = oldinputMax;
@ -745,12 +747,25 @@ startDocument(void *ctx)
"SAX.startDocument()\n");
#endif
if (ctxt->html) {
if (ctxt->myDoc == NULL)
#ifdef LIBXML_HTML_ENABLED
if (ctxt->myDoc == NULL)
ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
if (ctxt->myDoc == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.startDocument(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
}
#else
xmlGenericError(xmlGenericErrorContext,
"libxml2 built without HTML support\n");
ctxt->errNo = XML_ERR_INTERNAL_ERROR;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
#endif
} else {
doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
@ -760,6 +775,14 @@ startDocument(void *ctx)
else
doc->encoding = NULL;
doc->standalone = ctxt->standalone;
} else {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.startDocument(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
}
}
if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
@ -839,6 +862,17 @@ my_attribute(void *ctx, const xmlChar *fullname, const xmlChar *value,
* Split the full name into a namespace prefix and the tag name
*/
name = xmlSplitQName(ctxt, fullname, &ns);
if (name == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.startElement(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
if (ns != NULL)
xmlFree(ns);
return;
}
/*
* Do the last stage of the attribute normalization
@ -921,6 +955,18 @@ my_attribute(void *ctx, const xmlChar *fullname, const xmlChar *value,
val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
0,0,0);
ctxt->depth--;
if (val == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.startElement(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
xmlFree(ns);
if (name != NULL)
xmlFree(name);
return;
}
} else {
val = (xmlChar *) value;
}
@ -1200,14 +1246,19 @@ process_external_subset:
attr->elem, attr->name,
attr->prefix);
if ((tst == attr) || (tst == NULL)) {
xmlChar fn[50];
xmlChar *fulln;
if (attr->prefix != NULL) {
fulln = xmlStrdup(attr->prefix);
fulln = xmlStrcat(fulln, BAD_CAST ":");
fulln = xmlStrcat(fulln, attr->name);
} else {
fulln = xmlStrdup(attr->name);
fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50);
if (fulln == NULL) {
if ((ctxt->sax != NULL) &&
(ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.startElement(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
}
/*
@ -1229,7 +1280,8 @@ process_external_subset:
my_attribute(ctxt, fulln, attr->defaultValue,
prefix);
}
xmlFree(fulln);
if ((fulln != fn) && (fulln != attr->name))
xmlFree(fulln);
}
}
}
@ -1301,7 +1353,14 @@ startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
* an attribute at this level.
*/
ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL);
if (ret == NULL) return;
if (ret == NULL) {
if (prefix != NULL)
xmlFree(prefix);
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
}
if (ctxt->myDoc->children == NULL) {
#ifdef DEBUG_SAX_TREE
xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
@ -1587,6 +1646,9 @@ characters(void *ctx, const xmlChar *ch, int len)
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.characters(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return;
}
ctxt->nodemem = size;
@ -1596,7 +1658,14 @@ characters(void *ctx, const xmlChar *ch, int len)
ctxt->nodelen += len;
lastChild->content[ctxt->nodelen] = 0;
} else if (coalesceText) {
xmlTextConcat(lastChild, ch, len);
if (xmlTextConcat(lastChild, ch, len)) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.characters(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
}
if (ctxt->node->children != NULL) {
ctxt->nodelen = xmlStrlen(lastChild->content);
ctxt->nodemem = ctxt->nodelen + 1;
@ -1604,10 +1673,19 @@ characters(void *ctx, const xmlChar *ch, int len)
} else {
/* Mixed content, first time */
lastChild = xmlNewTextLen(ch, len);
xmlAddChild(ctxt->node, lastChild);
if (ctxt->node->children != NULL) {
ctxt->nodelen = len;
ctxt->nodemem = len + 1;
if (lastChild == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"SAX.characters(): out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
} else {
xmlAddChild(ctxt->node, lastChild);
if (ctxt->node->children != NULL) {
ctxt->nodelen = len;
ctxt->nodemem = len + 1;
}
}
}
}

407
check-relaxng-test-suite2.py Executable file
View File

@ -0,0 +1,407 @@
#!/usr/bin/python
import sys
import time
import os
import string
import StringIO
sys.path.append("python")
import libxml2
# Memory debug specific
libxml2.debugMemory(1)
debug = 0
#
# the testsuite description
#
CONF="test/relaxng/testsuite.xml"
LOG="check-relaxng-test-suite2.log"
log = open(LOG, "w")
nb_schemas_tests = 0
nb_schemas_success = 0
nb_schemas_failed = 0
nb_instances_tests = 0
nb_instances_success = 0
nb_instances_failed = 0
libxml2.lineNumbersDefault(1)
#
# Resolver callback
#
resources = {}
def resolver(URL, ID, ctxt):
global resources
if resources.has_key(URL):
return(StringIO.StringIO(resources[URL]))
log.write("Resolver failure: asked %s\n" % (URL))
log.write("resources: %s\n" % (resources))
return None
#
# Load the previous results
#
#results = {}
#previous = {}
#
#try:
# res = libxml2.parseFile(RES)
#except:
# log.write("Could not parse %s" % (RES))
#
# handle a valid instance
#
def handle_valid(node, schema):
global log
global nb_instances_success
global nb_instances_failed
instance = node.prop("dtd")
if instance == None:
instance = ""
child = node.children
while child != None:
if child.type != 'text':
instance = instance + child.serialize()
child = child.next
mem = libxml2.debugMemory(1);
try:
doc = libxml2.parseDoc(instance)
except:
doc = None
if doc == None:
log.write("\nFailed to parse correct instance:\n-----\n")
log.write(instance)
log.write("\n-----\n")
nb_instances_failed = nb_instances_failed + 1
return
if debug:
print "instance line %d" % (node.lineNo())
try:
ctxt = schema.relaxNGNewValidCtxt()
ret = doc.relaxNGValidateDoc(ctxt)
del ctxt
except:
ret = -1
doc.freeDoc()
if mem != libxml2.debugMemory(1):
print "validating instance %d line %d leaks" % (
nb_instances_tests, node.lineNo())
if ret != 0:
log.write("\nFailed to validate correct instance:\n-----\n")
log.write(instance)
log.write("\n-----\n")
nb_instances_failed = nb_instances_failed + 1
else:
nb_instances_success = nb_instances_success + 1
#
# handle an invalid instance
#
def handle_invalid(node, schema):
global log
global nb_instances_success
global nb_instances_failed
instance = node.prop("dtd")
if instance == None:
instance = ""
child = node.children
while child != None:
if child.type != 'text':
instance = instance + child.serialize()
child = child.next
mem = libxml2.debugMemory(1);
try:
doc = libxml2.parseDoc(instance)
except:
doc = None
if doc == None:
log.write("\nStrange: failed to parse incorrect instance:\n-----\n")
log.write(instance)
log.write("\n-----\n")
return
if debug:
print "instance line %d" % (node.lineNo())
try:
ctxt = schema.relaxNGNewValidCtxt()
ret = doc.relaxNGValidateDoc(ctxt)
del ctxt
except:
ret = -1
doc.freeDoc()
if mem != libxml2.debugMemory(1):
print "validating instance %d line %d leaks" % (
nb_instances_tests, node.lineNo())
if ret == 0:
log.write("\nFailed to detect validation problem in instance:\n-----\n")
log.write(instance)
log.write("\n-----\n")
nb_instances_failed = nb_instances_failed + 1
else:
nb_instances_success = nb_instances_success + 1
#
# handle an incorrect test
#
def handle_correct(node):
global log
global nb_schemas_success
global nb_schemas_failed
schema = ""
child = node.children
while child != None:
if child.type != 'text':
schema = schema + child.serialize()
child = child.next
try:
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
rngs = rngp.relaxNGParse()
except:
rngs = None
if rngs == None:
log.write("\nFailed to compile correct schema:\n-----\n")
log.write(schema)
log.write("\n-----\n")
nb_schemas_failed = nb_schemas_failed + 1
else:
nb_schemas_success = nb_schemas_success + 1
return rngs
def handle_incorrect(node):
global log
global nb_schemas_success
global nb_schemas_failed
schema = ""
child = node.children
while child != None:
if child.type != 'text':
schema = schema + child.serialize()
child = child.next
try:
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
rngs = rngp.relaxNGParse()
except:
rngs = None
if rngs != None:
log.write("\nFailed to detect schema error in:\n-----\n")
log.write(schema)
log.write("\n-----\n")
nb_schemas_failed = nb_schemas_failed + 1
else:
# log.write("\nSuccess detecting schema error in:\n-----\n")
# log.write(schema)
# log.write("\n-----\n")
nb_schemas_success = nb_schemas_success + 1
return None
#
# resource handling: keep a dictionary of URL->string mappings
#
def handle_resource(node, dir):
global resources
try:
name = node.prop('name')
except:
name = None
if name == None or name == '':
log.write("resource has no name")
return;
if dir != None:
# name = libxml2.buildURI(name, dir)
name = dir + '/' + name
res = ""
child = node.children
while child != None:
if child.type != 'text':
res = res + child.serialize()
child = child.next
resources[name] = res
#
# dir handling: pseudo directory resources
#
def handle_dir(node, dir):
try:
name = node.prop('name')
except:
name = None
if name == None or name == '':
log.write("resource has no name")
return;
if dir != None:
# name = libxml2.buildURI(name, dir)
name = dir + '/' + name
dirs = node.xpathEval('dir')
for dir in dirs:
handle_dir(dir, name)
res = node.xpathEval('resource')
for r in res:
handle_resource(r, name)
#
# handle a testCase element
#
def handle_testCase(node):
global nb_schemas_tests
global nb_instances_tests
global resources
sections = node.xpathEval('string(section)')
log.write("\n ======== test %d line %d section %s ==========\n" % (
nb_schemas_tests, node.lineNo(), sections))
resources = {}
if debug:
print "test %d line %d" % (nb_schemas_tests, node.lineNo())
dirs = node.xpathEval('dir')
for dir in dirs:
handle_dir(dir, None)
res = node.xpathEval('resource')
for r in res:
handle_resource(r, None)
tsts = node.xpathEval('incorrect')
if tsts != []:
if len(tsts) != 1:
print "warning test line %d has more than one <incorrect> example" %(node.lineNo())
schema = handle_incorrect(tsts[0])
else:
tsts = node.xpathEval('correct')
if tsts != []:
if len(tsts) != 1:
print "warning test line %d has more than one <correct> example"% (node.lineNo())
schema = handle_correct(tsts[0])
else:
print "warning <testCase> line %d has no <correct> nor <incorrect> child" % (node.lineNo())
nb_schemas_tests = nb_schemas_tests + 1;
valids = node.xpathEval('valid')
invalids = node.xpathEval('invalid')
nb_instances_tests = nb_instances_tests + len(valids) + len(invalids)
if schema != None:
for valid in valids:
handle_valid(valid, schema)
for invalid in invalids:
handle_invalid(invalid, schema)
#
# handle a testSuite element
#
def handle_testSuite(node, level = 0):
global nb_schemas_tests, nb_schemas_success, nb_schemas_failed
global nb_instances_tests, nb_instances_success, nb_instances_failed
if level >= 1:
old_schemas_tests = nb_schemas_tests
old_schemas_success = nb_schemas_success
old_schemas_failed = nb_schemas_failed
old_instances_tests = nb_instances_tests
old_instances_success = nb_instances_success
old_instances_failed = nb_instances_failed
docs = node.xpathEval('documentation')
authors = node.xpathEval('author')
if docs != []:
msg = ""
for doc in docs:
msg = msg + doc.content + " "
if authors != []:
msg = msg + "written by "
for author in authors:
msg = msg + author.content + " "
print msg
sections = node.xpathEval('section')
if sections != [] and level <= 0:
msg = ""
for section in sections:
msg = msg + section.content + " "
print "Tests for section %s" % (msg)
for test in node.xpathEval('testCase'):
handle_testCase(test)
for test in node.xpathEval('testSuite'):
handle_testSuite(test, level + 1)
if level >= 1 and sections != []:
msg = ""
for section in sections:
msg = msg + section.content + " "
print "Result of tests for section %s" % (msg)
if nb_schemas_tests != old_schemas_tests:
print "found %d test schemas: %d success %d failures" % (
nb_schemas_tests - old_schemas_tests,
nb_schemas_success - old_schemas_success,
nb_schemas_failed - old_schemas_failed)
if nb_instances_tests != old_instances_tests:
print "found %d test instances: %d success %d failures" % (
nb_instances_tests - old_instances_tests,
nb_instances_success - old_instances_success,
nb_instances_failed - old_instances_failed)
#
# Parse the conf file
#
libxml2.substituteEntitiesDefault(1);
testsuite = libxml2.parseFile(CONF)
#
# Error and warnng callbacks
#
def callback(ctx, str):
global log
log.write("%s%s" % (ctx, str))
libxml2.registerErrorHandler(callback, "")
libxml2.setEntityLoader(resolver)
root = testsuite.getRootElement()
if root.name != 'testSuite':
print "%s doesn't start with a testSuite element, aborting" % (CONF)
sys.exit(1)
print "Running Relax NG testsuite"
handle_testSuite(root)
print "\nTOTAL:\nfound %d test schemas: %d success %d failures" % (
nb_schemas_tests, nb_schemas_success, nb_schemas_failed)
print "found %d test instances: %d success %d failures" % (
nb_instances_tests, nb_instances_success, nb_instances_failed)
testsuite.freeDoc()
# Memory debug specific
libxml2.relaxNGCleanupTypes()
libxml2.cleanupParser()
if libxml2.debugMemory(1) == 0:
print "OK"
else:
print "Memory leak %d bytes" % (libxml2.debugMemory(1))
libxml2.dumpMemory()

View File

@ -802,7 +802,7 @@ int xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx,
/*
* Parser contexts handling.
*/
void xmlInitParserCtxt (xmlParserCtxtPtr ctxt);
int xmlInitParserCtxt (xmlParserCtxtPtr ctxt);
void xmlClearParserCtxt (xmlParserCtxtPtr ctxt);
void xmlFreeParserCtxt (xmlParserCtxtPtr ctxt);
void xmlSetupParserForBuffer (xmlParserCtxtPtr ctxt,

View File

@ -724,7 +724,7 @@ xmlNodePtr xmlAddNextSibling (xmlNodePtr cur,
void xmlUnlinkNode (xmlNodePtr cur);
xmlNodePtr xmlTextMerge (xmlNodePtr first,
xmlNodePtr second);
void xmlTextConcat (xmlNodePtr node,
int xmlTextConcat (xmlNodePtr node,
const xmlChar *content,
int len);
void xmlFreeNodeList (xmlNodePtr cur);

View File

@ -1720,6 +1720,8 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
*prefix = NULL;
if (cur == NULL) return(NULL);
#ifndef XML_XML_NAMESPACE
/* xml: prefix is not really a namespace */
if ((cur[0] == 'x') && (cur[1] == 'm') &&
@ -1905,6 +1907,14 @@ xmlParseName(xmlParserCtxtPtr ctxt) {
ctxt->input->cur = in;
ctxt->nbChars += count;
ctxt->input->col += count;
if (ret == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"XML parser: out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
}
return(ret);
}
}
@ -4581,6 +4591,15 @@ xmlParseElementChildrenContentDecl
return(NULL);
}
cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
if (cur == NULL) {
if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
ctxt->sax->error(ctxt->userData,
"xmlParseElementChildrenContentDecl : out of memory\n");
ctxt->errNo = XML_ERR_NO_MEMORY;
if (ctxt->recovery == 0) ctxt->disableSAX = 1;
xmlFree(elem);
return(NULL);
}
GROW;
if (RAW == '?') {
cur->ocur = XML_ELEMENT_CONTENT_OPT;
@ -6731,18 +6750,35 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) {
xmlGenericError(xmlGenericErrorContext,
"malloc of %ld byte failed\n",
maxatts * (long)sizeof(xmlChar *));
return(NULL);
if (attname != NULL)
xmlFree(attname);
if (attvalue != NULL)
xmlFree(attvalue);
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
goto failed;
}
} else if (nbatts + 4 > maxatts) {
const xmlChar **n;
maxatts *= 2;
atts = (const xmlChar **) xmlRealloc((void *) atts,
n = (const xmlChar **) xmlRealloc((void *) atts,
maxatts * sizeof(xmlChar *));
if (atts == NULL) {
if (n == NULL) {
xmlGenericError(xmlGenericErrorContext,
"realloc of %ld byte failed\n",
maxatts * (long)sizeof(xmlChar *));
return(NULL);
if (attname != NULL)
xmlFree(attname);
if (attvalue != NULL)
xmlFree(attvalue);
ctxt->errNo = XML_ERR_NO_MEMORY;
ctxt->instate = XML_PARSER_EOF;
ctxt->disableSAX = 1;
goto failed;
}
atts = n;
}
atts[nbatts++] = attname;
atts[nbatts++] = attvalue;
@ -6790,7 +6826,9 @@ failed:
ctxt->sax->startElement(ctxt->userData, name, atts);
if (atts != NULL) {
for (i = 0;i < nbatts;i++) xmlFree((xmlChar *) atts[i]);
for (i = 0;i < nbatts;i++)
if (atts[i] != NULL)
xmlFree((xmlChar *) atts[i]);
xmlFree((void *) atts);
}
return(name);
@ -8317,6 +8355,10 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
xmlParseGetLasts(ctxt, &lastlt, &lastgt);
while (1) {
if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
return(0);
/*
* Pop-up of finished entities.
*/
@ -9128,6 +9170,8 @@ done:
int
xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
int terminate) {
if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
return(ctxt->errNo);
if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
(ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) {
int base = ctxt->input->base - ctxt->input->buf->buffer->content;
@ -9163,6 +9207,8 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
}
}
xmlParseTryOrFinish(ctxt, terminate);
if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
return(ctxt->errNo);
if (terminate) {
/*
* Check for termination
@ -9259,7 +9305,9 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
ctxt = xmlNewParserCtxt();
if (ctxt == NULL) {
xmlFree(buf);
xmlGenericError(xmlGenericErrorContext,
"xml parser: out of memory\n");
xmlFreeParserInputBuffer(buf);
return(NULL);
}
if (sax != NULL) {
@ -9267,8 +9315,10 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
xmlFree(ctxt->sax);
ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler));
if (ctxt->sax == NULL) {
xmlFree(buf);
xmlFree(ctxt);
xmlGenericError(xmlGenericErrorContext,
"xml parser: out of memory\n");
xmlFreeParserInputBuffer(buf);
xmlFreeParserCtxt(ctxt);
return(NULL);
}
memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler));
@ -9284,7 +9334,7 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
inputStream = xmlNewInputStream(ctxt);
if (inputStream == NULL) {
xmlFreeParserCtxt(ctxt);
xmlFree(buf);
xmlFreeParserInputBuffer(buf);
return(NULL);
}

View File

@ -2166,15 +2166,17 @@ xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) {
* @ctxt: an XML parser context
*
* Initialize a parser context
*
* Returns 0 in case of success and -1 in case of error
*/
void
int
xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
{
if(ctxt==NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlInitParserCtxt: NULL context given\n");
return;
return(-1);
}
xmlDefaultSAXHandlerInit();
@ -2183,6 +2185,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
if (ctxt->sax == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlInitParserCtxt: out of memory\n");
return(-1);
}
else
memcpy(ctxt->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
@ -2196,7 +2199,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->inputNr = 0;
ctxt->inputMax = 0;
ctxt->input = NULL;
return;
return(-1);
}
ctxt->inputNr = 0;
ctxt->inputMax = 5;
@ -2224,7 +2227,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->inputNr = 0;
ctxt->inputMax = 0;
ctxt->input = NULL;
return;
return(-1);
}
ctxt->nodeNr = 0;
ctxt->nodeMax = 10;
@ -2244,7 +2247,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->nameNr = 0;
ctxt->nameMax = 0;
ctxt->name = NULL;
return;
return(-1);
}
ctxt->nameNr = 0;
ctxt->nameMax = 10;
@ -2267,7 +2270,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->spaceNr = 0;
ctxt->spaceMax = 0;
ctxt->space = NULL;
return;
return(-1);
}
ctxt->spaceNr = 1;
ctxt->spaceMax = 10;
@ -2305,6 +2308,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->charset = XML_CHAR_ENCODING_UTF8;
ctxt->catalogs = NULL;
xmlInitNodeInfoSeq(&ctxt->node_seq);
return(0);
}
/**
@ -2370,7 +2374,10 @@ xmlNewParserCtxt()
return(NULL);
}
memset(ctxt, 0, sizeof(xmlParserCtxt));
xmlInitParserCtxt(ctxt);
if (xmlInitParserCtxt(ctxt) < 0) {
xmlFreeParserCtxt(ctxt);
return(NULL);
}
return(ctxt);
}

183
testOOM.c Normal file
View File

@ -0,0 +1,183 @@
/*
* testOOM.c: Test out-of-memory handling
*
* See Copyright for the status of this software.
*
* hp@redhat.com
*/
/* FIXME this test would be much better if instead of just checking
* for debug spew or crashes on OOM, it also validated the expected
* results of parsing a particular file vs. the actual results
*/
#include "libxml.h"
#include <string.h>
#include <stdarg.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <libxml/xmlreader.h>
#include "testOOMlib.h"
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
int debug = 0;
int dump = 0;
int noent = 0;
int count = 0;
int valid = 0;
static void usage(const char *progname) {
printf("Usage : %s [options] XMLfiles ...\n", progname);
printf("\tParse the XML files using the xmlTextReader API\n");
printf("\t --count: count the number of attribute and elements\n");
printf("\t --valid: validate the document\n");
exit(1);
}
static int elem, attrs;
static int processNode(xmlTextReaderPtr reader) {
int type;
type = xmlTextReaderNodeType(reader);
if (count) {
if (type == 1) {
elem++;
attrs += xmlTextReaderAttributeCount(reader);
}
}
return TRUE;
}
/* This always returns TRUE since we don't validate the results of
* parsing a particular document vs. the expected results of parsing
* that document. The idea is that such a failure would return FALSE.
*/
static int
check_load_file_memory_func (void *data)
{
const char *filename = data;
xmlTextReaderPtr reader;
int ret;
if (count) {
elem = 0;
attrs = 0;
}
reader = xmlNewTextReaderFilename(filename);
if (reader != NULL) {
if (valid) {
if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1) == -1) {
xmlFreeTextReader (reader);
return TRUE;
}
}
/*
* Process all nodes in sequence
*/
ret = xmlTextReaderRead (reader);
while (TRUE) {
if (ret == -1) {
xmlFreeTextReader (reader);
return TRUE;
} else if (ret != 1)
break;
if (!processNode(reader)) {
xmlFreeTextReader (reader);
return FALSE;
}
ret = xmlTextReaderRead(reader);
}
/*
* Done, cleanup and status
*/
xmlFreeTextReader (reader);
return TRUE;
} else {
return TRUE;
}
}
int main(int argc, char **argv) {
int i;
int files = 0;
if (argc <= 1) {
usage(argv[0]);
return(1);
}
LIBXML_TEST_VERSION;
xmlMemSetup (test_free,
test_malloc,
test_realloc,
test_strdup);
for (i = 1; i < argc ; i++) {
if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
debug++;
else if ((!strcmp(argv[i], "-dump")) || (!strcmp(argv[i], "--dump")))
dump++;
else if ((!strcmp(argv[i], "-count")) || (!strcmp(argv[i], "--count")))
count++;
else if ((!strcmp(argv[i], "-valid")) || (!strcmp(argv[i], "--valid")))
valid++;
else if ((!strcmp(argv[i], "-noent")) ||
(!strcmp(argv[i], "--noent")))
noent++;
}
if (noent != 0)
xmlSubstituteEntitiesDefault(1);
for (i = 1; i < argc ; i++) {
if (argv[i][0] != '-') {
if (!test_oom_handling (check_load_file_memory_func,
argv[i])) {
fprintf (stderr, "Failed!\n");
return (1);
}
xmlCleanupParser();
if (test_get_malloc_blocks_outstanding () > 0) {
fprintf (stderr, "%d blocks leaked\n",
test_get_malloc_blocks_outstanding ());
xmlMemoryDump();
return (1);
}
files ++;
}
}
xmlMemoryDump();
return(0);
}

260
testOOMlib.c Normal file
View File

@ -0,0 +1,260 @@
/*
* testOOM.c: Test out-of-memory handling
*
* See Copyright for the status of this software.
*
* Copyright 2003 Red Hat, Inc.
* Written by: hp@redhat.com
*/
#include "testOOMlib.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <string.h>
#define _TEST_INT_MAX 2147483647
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
#include <libxml/xmlmemory.h>
static int fail_alloc_counter = _TEST_INT_MAX;
static int n_failures_per_failure = 1;
static int n_failures_this_failure = 0;
static int n_blocks_outstanding = 0;
/**
* Sets the number of allocations until we simulate a failed
* allocation. If set to 0, the next allocation to run
* fails; if set to 1, one succeeds then the next fails; etc.
* Set to _TEST_INT_MAX to not fail anything.
*
* @param until_next_fail number of successful allocs before one fails
*/
static void
set_fail_alloc_counter (int until_next_fail)
{
fail_alloc_counter = until_next_fail;
}
/**
* Gets the number of successful allocs until we'll simulate
* a failed alloc.
*
* @returns current counter value
*/
static int
get_fail_alloc_counter (void)
{
return fail_alloc_counter;
}
/**
* Sets how many mallocs to fail when the fail alloc counter reaches
* 0.
*
* @param number to fail
*/
static void
set_fail_alloc_failures (int failures_per_failure)
{
n_failures_per_failure = failures_per_failure;
}
/**
* Called when about to alloc some memory; if
* it returns #TRUE, then the allocation should
* fail. If it returns #FALSE, then the allocation
* should not fail.
*
* @returns #TRUE if this alloc should fail
*/
static int
decrement_fail_alloc_counter (void)
{
if (fail_alloc_counter <= 0)
{
n_failures_this_failure += 1;
if (n_failures_this_failure >= n_failures_per_failure)
{
fail_alloc_counter = _TEST_INT_MAX;
n_failures_this_failure = 0;
}
return TRUE;
}
else
{
fail_alloc_counter -= 1;
return FALSE;
}
}
/**
* Get the number of outstanding malloc()'d blocks.
*
* @returns number of blocks
*/
int
test_get_malloc_blocks_outstanding (void)
{
return n_blocks_outstanding;
}
void*
test_malloc (size_t bytes)
{
if (decrement_fail_alloc_counter ())
{
/* FAIL the malloc */
return NULL;
}
if (bytes == 0) /* some system mallocs handle this, some don't */
return NULL;
else
{
void *mem;
mem = xmlMemMalloc (bytes);
if (mem)
n_blocks_outstanding += 1;
return mem;
}
}
void*
test_realloc (void *memory,
size_t bytes)
{
if (decrement_fail_alloc_counter ())
{
/* FAIL */
return NULL;
}
if (bytes == 0) /* guarantee this is safe */
{
test_free (memory);
return NULL;
}
else
{
void *mem;
mem = xmlMemRealloc (memory, bytes);
if (memory == NULL && mem != NULL)
n_blocks_outstanding += 1;
return mem;
}
}
void
test_free (void *memory)
{
if (memory) /* we guarantee it's safe to free (NULL) */
{
n_blocks_outstanding -= 1;
xmlMemFree (memory);
}
}
char*
test_strdup (const char *str)
{
int len;
char *copy;
if (str == NULL)
return NULL;
len = strlen (str);
copy = test_malloc (len + 1);
if (copy == NULL)
return NULL;
memcpy (copy, str, len + 1);
return copy;
}
static int
run_failing_each_malloc (int n_mallocs,
TestMemoryFunction func,
void *data)
{
n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */
while (n_mallocs >= 0)
{
set_fail_alloc_counter (n_mallocs);
if (!(* func) (data))
return FALSE;
n_mallocs -= 1;
}
set_fail_alloc_counter (_TEST_INT_MAX);
return TRUE;
}
/**
* Tests how well the given function responds to out-of-memory
* situations. Calls the function repeatedly, failing a different
* call to malloc() each time. If the function ever returns #FALSE,
* the test fails. The function should return #TRUE whenever something
* valid (such as returning an error, or succeeding) occurs, and #FALSE
* if it gets confused in some way.
*
* @param func function to call
* @param data data to pass to function
* @returns #TRUE if the function never returns FALSE
*/
int
test_oom_handling (TestMemoryFunction func,
void *data)
{
int approx_mallocs;
/* Run once to see about how many mallocs are involved */
set_fail_alloc_counter (_TEST_INT_MAX);
if (!(* func) (data))
return FALSE;
approx_mallocs = _TEST_INT_MAX - get_fail_alloc_counter ();
set_fail_alloc_failures (1);
if (!run_failing_each_malloc (approx_mallocs, func, data))
return FALSE;
set_fail_alloc_failures (2);
if (!run_failing_each_malloc (approx_mallocs, func, data))
return FALSE;
set_fail_alloc_failures (3);
if (!run_failing_each_malloc (approx_mallocs, func, data))
return FALSE;
set_fail_alloc_counter (_TEST_INT_MAX);
return TRUE;
}

26
testOOMlib.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef TEST_OOM_LIB_H
#define TEST_OOM_LIB_H
#include <config.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
void* test_malloc (size_t bytes);
void* test_realloc (void *memory,
size_t bytes);
void test_free (void *memory);
char* test_strdup (const char *str);
/* returns true on success */
typedef int (* TestMemoryFunction) (void *data);
/* returns true on success */
int test_oom_handling (TestMemoryFunction func,
void *data);
/* get number of blocks leaked */
int test_get_malloc_blocks_outstanding (void);
#endif

28
tree.c
View File

@ -193,6 +193,7 @@ xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
xmlChar *ret = NULL;
*prefix = NULL;
if (name == NULL) return(NULL);
#ifndef XML_XML_NAMESPACE
/* xml: prefix is not really a namespace */
@ -216,7 +217,21 @@ xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
return(NULL);
*prefix = xmlStrndup(name, len);
if (*prefix == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlSplitQName2 : out of memory!\n");
return(NULL);
}
ret = xmlStrdup(&name[len + 1]);
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlSplitQName2 : out of memory!\n");
if (*prefix != NULL) {
xmlFree(*prefix);
*prefix = NULL;
}
return(NULL);
}
return(ret);
}
@ -1670,6 +1685,7 @@ xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
if (cur == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlNewNsPropEatName : malloc failed\n");
xmlFree(name);
return(NULL);
}
memset(cur, 0, sizeof(xmlAttr));
@ -1988,6 +2004,7 @@ xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
if (cur == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlNewNode : malloc failed\n");
xmlFree(name);
return(NULL);
}
memset(cur, 0, sizeof(xmlNode));
@ -6047,11 +6064,13 @@ xmlIsBlankNode(xmlNodePtr node) {
* @len: @content length
*
* Concat the given string at the end of the existing node content
*
* Returns -1 in case of error, 0 otherwise
*/
void
int
xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
if (node == NULL) return;
if (node == NULL) return(-1);
if ((node->type != XML_TEXT_NODE) &&
(node->type != XML_CDATA_SECTION_NODE)) {
@ -6059,9 +6078,12 @@ xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
xmlGenericError(xmlGenericErrorContext,
"xmlTextConcat: node is not text nor CDATA\n");
#endif
return;
return(-1);
}
node->content = xmlStrncat(node->content, content, len);
if (node->content == NULL)
return(-1);
return(0);
}
/************************************************************************

3
uri.c
View File

@ -1992,6 +1992,9 @@ xmlCanonicPath(const xmlChar *path)
}
uri = xmlCreateURI();
if (uri == NULL) {
return(NULL);
}
#if defined(_WIN32) && !defined(__CYGWIN__)
len = xmlStrlen(path);

83
valid.c
View File

@ -59,24 +59,27 @@ typedef struct _xmlValidState {
static int
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
if (ctxt->vstateMax == 0) {
if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
ctxt->vstateMax = 10;
ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
sizeof(ctxt->vstateTab[0]));
if (ctxt->vstateTab == NULL) {
VERROR(ctxt->userData, "realloc failed !n");
VERROR(ctxt->userData, "malloc failed !n");
return(-1);
}
}
if (ctxt->vstateNr >= ctxt->vstateMax) {
ctxt->vstateMax *= 2;
ctxt->vstateTab = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
if (ctxt->vstateTab == NULL) {
xmlValidState *tmp;
tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
if (tmp == NULL) {
VERROR(ctxt->userData, "realloc failed !n");
return(-1);
}
ctxt->vstateMax *= 2;
ctxt->vstateTab = tmp;
}
ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
@ -161,15 +164,28 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
if (ctxt->vstateNr > MAX_RECURSE) {
return(-1);
}
if (ctxt->vstateTab == NULL) {
ctxt->vstateMax = 8;
ctxt->vstateTab = (xmlValidState *) xmlMalloc(
ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
if (ctxt->vstateTab == NULL) {
xmlGenericError(xmlGenericErrorContext,
"malloc failed !n");
return(-1);
}
}
if (ctxt->vstateNr >= ctxt->vstateMax) {
ctxt->vstateMax *= 2;
ctxt->vstateTab = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
if (ctxt->vstateTab == NULL) {
xmlValidState *tmp;
tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
if (tmp == NULL) {
xmlGenericError(xmlGenericErrorContext,
"realloc failed !n");
return(-1);
}
ctxt->vstateMax *= 2;
ctxt->vstateTab = tmp;
ctxt->vstate = &ctxt->vstateTab[0];
}
/*
@ -219,15 +235,15 @@ nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
}
}
if (ctxt->nodeNr >= ctxt->nodeMax) {
ctxt->nodeMax *= 2;
ctxt->nodeTab =
(xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
ctxt->nodeMax *
sizeof(ctxt->nodeTab[0]));
if (ctxt->nodeTab == NULL) {
xmlNodePtr *tmp;
tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
if (tmp == NULL) {
xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
return (0);
}
ctxt->nodeMax *= 2;
ctxt->nodeTab = tmp;
}
ctxt->nodeTab[ctxt->nodeNr] = value;
ctxt->node = value;
@ -635,7 +651,7 @@ xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
xmlAutomataSetFinalState(ctxt->am, ctxt->state);
elem->contModel = xmlAutomataCompile(ctxt->am);
if (!xmlRegexpIsDeterminist(elem->contModel)) {
if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
char expr[5000];
expr[0] = 0;
xmlSnprintfElementContent(expr, 5000, elem->content, 1);
@ -901,7 +917,8 @@ xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int
strcat(buf, " ...");
return;
}
strcat(buf, (char *) content->name);
if (content->name != NULL)
strcat(buf, (char *) content->name);
break;
case XML_ELEMENT_CONTENT_SEQ:
if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
@ -1086,6 +1103,10 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
if (table == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlAddElementDecl: Table creation failed!\n");
if (uqname != NULL)
xmlFree(uqname);
if (ns != NULL)
xmlFree(ns);
return(NULL);
}
@ -1116,6 +1137,8 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
VERROR(ctxt->userData, "Redefinition of element %s\n", name);
if (uqname != NULL)
xmlFree(uqname);
if (ns != NULL)
xmlFree(ns);
return(NULL);
}
} else {
@ -1123,6 +1146,10 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlAddElementDecl: out of memory\n");
if (uqname != NULL)
xmlFree(uqname);
if (ns != NULL)
xmlFree(ns);
return(NULL);
}
memset(ret, 0, sizeof(xmlElement));
@ -1132,6 +1159,16 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
* fill the structure.
*/
ret->name = xmlStrdup(name);
if (ret->name == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlAddElementDecl: out of memory\n");
if (uqname != NULL)
xmlFree(uqname);
if (ns != NULL)
xmlFree(ns);
xmlFree(ret);
return(NULL);
}
ret->prefix = ns;
/*
@ -2667,7 +2704,7 @@ xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
xmlElementPtr cur;
xmlChar *uqname = NULL, *prefix = NULL;
if (dtd == NULL) return(NULL);
if ((dtd == NULL) || (name == NULL)) return(NULL);
if (dtd->elements == NULL)
return(NULL);
table = (xmlElementTablePtr) dtd->elements;
@ -4641,7 +4678,7 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
if (elemDecl->contModel == NULL)
ret = xmlValidBuildContentModel(ctxt, elemDecl);
if (elemDecl->contModel == NULL) {
ret = -1;
return(-1);
} else {
xmlRegExecCtxtPtr exec;
@ -4837,14 +4874,14 @@ fail:
char list[5000];
expr[0] = 0;
xmlSnprintfElementContent(expr, 5000, cont, 1);
xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
list[0] = 0;
#ifndef LIBXML_REGEXP_ENABLED
if (repl != NULL)
xmlSnprintfElements(list, 5000, repl, 1);
xmlSnprintfElements(&list[0], 5000, repl, 1);
else
#endif /* LIBXML_REGEXP_ENABLED */
xmlSnprintfElements(list, 5000, child, 1);
xmlSnprintfElements(&list[0], 5000, child, 1);
if (name != NULL) {
if (parent != NULL) VECTXT(ctxt, parent);

View File

@ -305,6 +305,8 @@ xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
unsigned long number;
if (!xmlMemInitialized) xmlInitMemory();
if (ptr == NULL)
return(NULL);
TEST_POINT
p = CLIENT_2_HDR(ptr);

View File

@ -83,7 +83,8 @@ typedef enum {
XML_TEXTREADER_END= 2,
XML_TEXTREADER_EMPTY= 3,
XML_TEXTREADER_BACKTRACK= 4,
XML_TEXTREADER_DONE= 5
XML_TEXTREADER_DONE= 5,
XML_TEXTREADER_ERROR= 6
} xmlTextReaderState;
typedef enum {
@ -417,6 +418,7 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) {
s, 1);
reader->cur = inbuf->use;
reader->mode = XML_TEXTREADER_DONE;
if (val != 0) return(-1);
}
}
reader->state = oldstate;
@ -1151,11 +1153,17 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
ret->base = 0;
ret->cur = 0;
}
if (ret->ctxt == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlNewTextReader : malloc failed\n");
xmlFree(ret->sax);
xmlFree(ret);
return(NULL);
}
ret->ctxt->_private = ret;
ret->ctxt->linenumbers = 1;
ret->allocs = XML_TEXTREADER_CTXT;
return(ret);
}
/**

View File

@ -332,23 +332,19 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
xmlRegexpPtr ret;
ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp));
if (ret == NULL)
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"out of memory compiling regexp\n");
return(NULL);
}
memset(ret, 0, sizeof(xmlRegexp));
ret->string = ctxt->string;
ctxt->string = NULL;
ret->nbStates = ctxt->nbStates;
ctxt->nbStates = 0;
ret->states = ctxt->states;
ctxt->states = NULL;
ret->nbAtoms = ctxt->nbAtoms;
ctxt->nbAtoms = 0;
ret->atoms = ctxt->atoms;
ctxt->atoms = NULL;
ret->nbCounters = ctxt->nbCounters;
ctxt->nbCounters = 0;
ret->counters = ctxt->counters;
ctxt->counters = NULL;
ret->determinist = ctxt->determinist;
if ((ret->determinist != 0) &&
@ -373,6 +369,12 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
*/
stateRemap = xmlMalloc(ret->nbStates * sizeof(int));
if (stateRemap == NULL) {
xmlGenericError(xmlGenericErrorContext,
"out of memory compiling regexp\n");
xmlFree(ret);
return(NULL);
}
for (i = 0;i < ret->nbStates;i++) {
if (ret->states[i] != NULL) {
stateRemap[i] = nbstates;
@ -385,7 +387,22 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
printf("Final: %d states\n", nbstates);
#endif
stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *));
if (stringMap == NULL) {
xmlGenericError(xmlGenericErrorContext,
"out of memory compiling regexp\n");
xmlFree(stateRemap);
xmlFree(ret);
return(NULL);
}
stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int));
if (stringRemap == NULL) {
xmlGenericError(xmlGenericErrorContext,
"out of memory compiling regexp\n");
xmlFree(stringMap);
xmlFree(stateRemap);
xmlFree(ret);
return(NULL);
}
for (i = 0;i < ret->nbAtoms;i++) {
if ((ret->atoms[i]->type == XML_REGEXP_STRING) &&
(ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) {
@ -399,6 +416,15 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
if (j >= nbatoms) {
stringRemap[i] = nbatoms;
stringMap[nbatoms] = xmlStrdup(value);
if (stringMap[nbatoms] == NULL) {
for (i = 0;i < nbatoms;i++)
xmlFree(stringMap[i]);
xmlFree(stringRemap);
xmlFree(stringMap);
xmlFree(stateRemap);
xmlFree(ret);
return(NULL);
}
nbatoms++;
}
} else {
@ -407,20 +433,29 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
for (i = 0;i < nbatoms;i++)
xmlFree(stringMap[i]);
xmlFree(stringMap);
goto fail_compact;
xmlFree(ret);
return(NULL);
}
}
#ifdef DEBUG_COMPACTION
printf("Final: %d atoms\n", nbatoms);
#endif
transitions = (int *) xmlMalloc((nbstates + 1) *
(nbatoms + 1) * sizeof(int));
if (transitions == NULL) {
xmlFree(stateRemap);
xmlFree(stringRemap);
xmlFree(stringMap);
xmlFree(ret);
return(NULL);
}
memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int));
/*
* Allocate the transition table. The first entry for each
* state correspond to the state type.
*/
transitions = (int *) xmlMalloc(nbstates * (nbatoms + 1) * sizeof(int));
transdata = NULL;
memset(transitions, 0, nbstates * (nbatoms + 1) * sizeof(int));
for (i = 0;i < ret->nbStates;i++) {
int stateno, atomno, targetno, prev;
@ -445,6 +480,11 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
if (transdata != NULL)
memset(transdata, 0,
nbstates * nbatoms * sizeof(void *));
else {
xmlGenericError(xmlGenericErrorContext,
"out of memory compiling regexp\n");
break;
}
}
targetno = stateRemap[trans->to];
/*
@ -470,7 +510,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
for (i = 0;i < nbatoms;i++)
xmlFree(stringMap[i]);
xmlFree(stringMap);
goto fail_compact;
goto not_determ;
}
} else {
#if 0
@ -524,7 +564,14 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
xmlFree(stateRemap);
xmlFree(stringRemap);
}
fail_compact:
not_determ:
ctxt->string = NULL;
ctxt->nbStates = 0;
ctxt->states = NULL;
ctxt->nbAtoms = 0;
ctxt->atoms = NULL;
ctxt->nbCounters = 0;
ctxt->counters = NULL;
return(ret);
}
@ -1048,11 +1095,11 @@ xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) {
return(ctxt->nbCounters++);
}
static void
static int
xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
if (atom == NULL) {
ERROR("atom push: atom is NULL");
return;
return(-1);
}
if (ctxt->maxAtoms == 0) {
ctxt->maxAtoms = 4;
@ -1061,7 +1108,7 @@ xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
if (ctxt->atoms == NULL) {
ERROR("atom push: allocation failed");
ctxt->maxAtoms = 0;
return;
return(-1);
}
} else if (ctxt->nbAtoms >= ctxt->maxAtoms) {
xmlRegAtomPtr *tmp;
@ -1071,12 +1118,13 @@ xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
if (tmp == NULL) {
ERROR("atom push: allocation failed");
ctxt->maxAtoms /= 2;
return;
return(-1);
}
ctxt->atoms = tmp;
}
atom->no = ctxt->nbAtoms;
ctxt->atoms[ctxt->nbAtoms++] = atom;
return(0);
}
static void
@ -1132,8 +1180,9 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
state->nbTrans++;
}
static void
static int
xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
if (state == NULL) return(-1);
if (ctxt->maxStates == 0) {
ctxt->maxStates = 4;
ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates *
@ -1141,7 +1190,7 @@ xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
if (ctxt->states == NULL) {
ERROR("add range: allocation failed");
ctxt->maxStates = 0;
return;
return(-1);
}
} else if (ctxt->nbStates >= ctxt->maxStates) {
xmlRegStatePtr *tmp;
@ -1151,12 +1200,13 @@ xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
if (tmp == NULL) {
ERROR("add range: allocation failed");
ctxt->maxStates /= 2;
return;
return(-1);
}
ctxt->states = tmp;
}
state->no = ctxt->nbStates;
ctxt->states[ctxt->nbStates++] = state;
return(0);
}
/**
@ -1245,20 +1295,23 @@ xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt,
* @to: the target state or NULL for building a new one
* @atom: the atom generating the transition
*
* Returns 0 if succes and -1 in case of error.
*/
static void
static int
xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
xmlRegStatePtr to, xmlRegAtomPtr atom) {
if (atom == NULL) {
ERROR("genrate transition: atom == NULL");
return;
return(-1);
}
if (atom->type == XML_REGEXP_SUBREG) {
/*
* this is a subexpression handling one should not need to
* create a new node excep for XML_REGEXP_QUANT_RANGE.
*/
xmlRegAtomPush(ctxt, atom);
if (xmlRegAtomPush(ctxt, atom) < 0) {
return(-1);
}
if ((to != NULL) && (atom->stop != to) &&
(atom->quant != XML_REGEXP_QUANT_RANGE)) {
/*
@ -1314,14 +1367,20 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
default:
break;
}
return;
return(0);
} else {
if (to == NULL) {
to = xmlRegNewState(ctxt);
xmlRegStatePush(ctxt, to);
if (to != NULL)
xmlRegStatePush(ctxt, to);
else {
return(-1);
}
}
if (xmlRegAtomPush(ctxt, atom) < 0) {
return(-1);
}
xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1);
xmlRegAtomPush(ctxt, atom);
ctxt->state = to;
}
switch (atom->quant) {
@ -1341,6 +1400,7 @@ xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
default:
break;
}
return(0);
}
/**
@ -1433,6 +1493,9 @@ xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
int statenr, transnr;
xmlRegStatePtr state;
if (ctxt->states == NULL) return;
/*
* build the completed transitions bypassing the epsilons
* Use a marking algorithm to avoid loops
@ -2276,6 +2339,8 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) {
if (comp == NULL)
return(NULL);
if ((comp->compact == NULL) && (comp->states == NULL))
return(NULL);
exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt));
if (exec == NULL) {
return(NULL);
@ -3568,6 +3633,8 @@ xmlFAParseCharClass(xmlRegParserCtxtPtr ctxt) {
* @ctxt: a regexp parser context
*
* [8] QuantExact ::= [0-9]+
*
* Returns 0 if success or -1 in case of error
*/
static int
xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) {
@ -3723,8 +3790,9 @@ xmlFAParsePiece(xmlRegParserCtxtPtr ctxt) {
* @first: is taht the first
*
* [2] branch ::= piece*
8
*/
static void
static int
xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
xmlRegStatePtr previous;
xmlRegAtomPtr prevatom = NULL;
@ -3734,7 +3802,8 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
ret = xmlFAParsePiece(ctxt);
if (ret != 0) {
if (first) {
xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom);
if (xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom) < 0)
return(-1);
previous = ctxt->state;
} else {
prevatom = ctxt->atom;
@ -3745,9 +3814,13 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
ret = xmlFAParsePiece(ctxt);
if (ret != 0) {
if (first) {
xmlFAGenerateTransitions(ctxt, previous, NULL, ctxt->atom);
if (xmlFAGenerateTransitions(ctxt, previous, NULL,
ctxt->atom) < 0)
return(-1);
} else {
xmlFAGenerateTransitions(ctxt, previous, NULL, prevatom);
if (xmlFAGenerateTransitions(ctxt, previous, NULL,
prevatom) < 0)
return(-1);
prevatom = ctxt->atom;
}
previous = ctxt->state;
@ -3755,8 +3828,10 @@ xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, int first) {
}
}
if (!first) {
xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom);
if (xmlFAGenerateTransitions(ctxt, previous, ctxt->end, prevatom) < 0)
return(-1);
}
return(0);
}
/**
@ -3994,7 +4069,15 @@ xmlNewAutomata(void) {
/* initialize the parser */
ctxt->end = NULL;
ctxt->start = ctxt->state = xmlRegNewState(ctxt);
xmlRegStatePush(ctxt, ctxt->start);
if (ctxt->start == NULL) {
xmlFreeAutomata(ctxt);
return(NULL);
}
if (xmlRegStatePush(ctxt, ctxt->start) < 0) {
xmlRegFreeState(ctxt->start);
xmlFreeAutomata(ctxt);
return(NULL);
}
return(ctxt);
}
@ -4067,12 +4150,17 @@ xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from,
if ((am == NULL) || (from == NULL) || (token == NULL))
return(NULL);
atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
if (atom == NULL)
return(NULL);
atom->data = data;
if (atom == NULL)
return(NULL);
atom->valuep = xmlStrdup(token);
xmlFAGenerateTransitions(am, from, to, atom);
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
xmlRegFreeAtom(atom);
return(NULL);
}
if (to == NULL)
return(am->state);
return(to);
@ -4127,7 +4215,10 @@ xmlAutomataNewTransition2(xmlAutomataPtr am, xmlAutomataStatePtr from,
atom->valuep = str;
}
xmlFAGenerateTransitions(am, from, to, atom);
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
xmlRegFreeAtom(atom);
return(NULL);
}
if (to == NULL)
return(am->state);
return(to);
@ -4173,7 +4264,10 @@ xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
atom->min = min;
atom->max = max;
xmlFAGenerateTransitions(am, from, to, atom);
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
xmlRegFreeAtom(atom);
return(NULL);
}
if (to == NULL)
to = am->state;
if (to == NULL)
@ -4400,6 +4494,7 @@ xmlRegexpPtr
xmlAutomataCompile(xmlAutomataPtr am) {
xmlRegexpPtr ret;
if ((am == NULL) || (am->error != 0)) return(NULL);
xmlFAEliminateEpsilonTransitions(am);
/* xmlFAComputesDeterminism(am); */
ret = xmlRegEpxFromParse(am);