mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-03-05 16:58:17 +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:
parent
18f113da8c
commit
a76fe5ca11
11
ChangeLog
11
ChangeLog
@ -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
|
||||
|
@ -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
106
SAX.c
@ -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
407
check-relaxng-test-suite2.py
Executable 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()
|
@ -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,
|
||||
|
@ -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);
|
||||
|
68
parser.c
68
parser.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
183
testOOM.c
Normal 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
260
testOOMlib.c
Normal 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
26
testOOMlib.h
Normal 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
28
tree.c
@ -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
3
uri.c
@ -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
83
valid.c
@ -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);
|
||||
|
@ -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);
|
||||
|
12
xmlreader.c
12
xmlreader.c
@ -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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
165
xmlregexp.c
165
xmlregexp.c
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user