aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@src.gnome.org>2004-11-02 14:52:23 +0000
committerDaniel Veillard <veillard@src.gnome.org>2004-11-02 14:52:23 +0000
commit36e5cd5064d3477a0500f6183d68b18b7493568a (patch)
tree95d13002a3bca1191e1328de0739dacbb15835ee
parent032268145fad72bbf00c944c1f6a067e5da4a1e0 (diff)
downloadandroid_external_libxml2-36e5cd5064d3477a0500f6183d68b18b7493568a.tar.gz
android_external_libxml2-36e5cd5064d3477a0500f6183d68b18b7493568a.tar.bz2
android_external_libxml2-36e5cd5064d3477a0500f6183d68b18b7493568a.zip
adding xmlMemBlocks() work on generator of an automatic API regression
* xmlmemory.c include/libxml/xmlmemory.h: adding xmlMemBlocks() * Makefile.am gentest.py testapi.c: work on generator of an automatic API regression test tool. * SAX2.c nanoftp.c parser.c parserInternals.c tree.c xmlIO.c xmlstring.c: various API hardeing changes as a result of running teh first set of automatic API regression tests. * test/slashdot16.xml: apparently missing from CVS, commited it Daniel
-rw-r--r--ChangeLog10
-rw-r--r--HTMLtree.c6
-rw-r--r--Makefile.am10
-rw-r--r--SAX2.c4
-rwxr-xr-xgentest.py556
-rw-r--r--include/libxml/xmlmemory.h2
-rw-r--r--nanoftp.c12
-rw-r--r--parser.c47
-rw-r--r--parserInternals.c33
-rw-r--r--test/slashdot16.xmlbin0 -> 10374 bytes
-rw-r--r--tree.c15
-rw-r--r--xmlIO.c3
-rw-r--r--xmlmemory.c20
-rw-r--r--xmlstring.c4
14 files changed, 697 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index f3cd9046..491d988e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Tue Nov 2 15:49:34 CET 2004 Daniel Veillard <daniel@veillard.com>
+
+ * xmlmemory.c include/libxml/xmlmemory.h: adding xmlMemBlocks()
+ * Makefile.am gentest.py testapi.c: work on generator of an
+ automatic API regression test tool.
+ * SAX2.c nanoftp.c parser.c parserInternals.c tree.c xmlIO.c
+ xmlstring.c: various API hardeing changes as a result of running
+ teh first set of automatic API regression tests.
+ * test/slashdot16.xml: apparently missing from CVS, commited it
+
Mon Nov 1 15:54:18 CET 2004 Daniel Veillard <daniel@veillard.com>
* xpath.c: fixed an UTF-8 parsing bug reported by Markus Bertheau
diff --git a/HTMLtree.c b/HTMLtree.c
index 9a5d35fe..dc0b0f5e 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -1053,6 +1053,9 @@ htmlSaveFile(const char *filename, xmlDocPtr cur) {
const char *encoding;
int ret;
+ if ((cur == NULL) || (filename == NULL))
+ return(-1);
+
xmlInitParser();
encoding = (const char *) htmlGetMetaEncoding(cur);
@@ -1113,6 +1116,9 @@ htmlSaveFileFormat(const char *filename, xmlDocPtr cur,
xmlCharEncodingHandlerPtr handler = NULL;
int ret;
+ if ((cur == NULL) || (filename == NULL))
+ return(-1);
+
xmlInitParser();
if (encoding != NULL) {
diff --git a/Makefile.am b/Makefile.am
index 583e812a..a6115bd1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@ INCLUDES = -I$(top_builddir)/include -I@srcdir@/include @THREAD_CFLAGS@ @Z_CFLAG
noinst_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath testURI \
testThreads testC14N testAutomata testRegexp \
- testReader
+ testReader testapi
bin_PROGRAMS = xmllint xmlcatalog
@@ -113,6 +113,14 @@ testReader_LDFLAGS =
testReader_DEPENDENCIES = $(DEPS)
testReader_LDADD= $(LDADDS)
+testapi.c: gentest.py doc/libxml2-api.xml
+ -@(if [ "$(PYTHON)" != "" ] ; then $(PYTHON) gentest.py ; fi )
+
+testapi_SOURCES=testapi.c
+testapi_LDFLAGS =
+testapi_DEPENDENCIES = $(DEPS)
+testapi_LDADD= $(LDADDS)
+
#testOOM_SOURCES=testOOM.c testOOMlib.h testOOMlib.c
#testOOM_LDFLAGS =
#testOOM_DEPENDENCIES = $(DEPS)
diff --git a/SAX2.c b/SAX2.c
index af36df9d..f3926600 100644
--- a/SAX2.c
+++ b/SAX2.c
@@ -890,7 +890,9 @@ xmlSAX2EndDocument(void *ctx)
ctxt->myDoc->encoding = ctxt->encoding;
ctxt->encoding = NULL;
}
- if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
+ if ((ctxt->inputTab != NULL) &&
+ (ctxt->inputNr > 0) && (ctxt->inputTab[0] != NULL) &&
+ (ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
(ctxt->myDoc->encoding == NULL)) {
ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
}
diff --git a/gentest.py b/gentest.py
new file mode 100755
index 00000000..7732d16a
--- /dev/null
+++ b/gentest.py
@@ -0,0 +1,556 @@
+#!/usr/bin/python -u
+#
+# generate a tester program for the API
+#
+import sys
+import string
+try:
+ import libxml2
+except:
+ print "libxml2 python bindings not available, skipping testapi.c generation"
+ sys.exit(0)
+
+#
+# Modules we don't want skip in API test
+#
+skipped_modules = [ "SAX", "SAX2", "xlink", "threads", "globals",
+ "xpathInternals", "xmlunicode", "parserInternals", "xmlmemory",
+ "xmlversion", "debugXML" ]
+
+#
+# Some function really need to be skipped for the tests.
+#
+skipped_functions = [ "xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
+ "xmlCleanupParser" ]
+
+#
+# Those functions have side effect on the global state
+# and hence generate errors on memory allocation tests
+#
+skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
+ "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
+ "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
+ "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
+ "xmlInitCharEncodingHandlers" ]
+
+modules = []
+
+def is_skipped_module(name):
+ for mod in skipped_modules:
+ if mod == name:
+ return 1
+ return 0
+
+def is_skipped_function(name):
+ for fun in skipped_functions:
+ if fun == name:
+ return 1
+ # Do not test destructors
+ if string.find(name, 'Free') != -1:
+ return 1
+ return 0
+
+def is_skipped_memcheck(name):
+ for fun in skipped_memcheck:
+ if fun == name:
+ return 1
+ return 0
+
+missing_types = {}
+def add_missing_type(name, func):
+ try:
+ list = missing_types[name]
+ list.append(func)
+ except:
+ missing_types[name] = [func]
+
+#
+# Open the input API description and the C test program result
+#
+doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
+if doc == None:
+ print "Failed to load doc/libxml2-api.xml"
+ sys.exit(1)
+test = open('testapi.c', 'w')
+ctxt = doc.xpathNewContext()
+headers = ctxt.xpathEval("/api/files/file")
+
+#
+# Generate the test header
+#
+test.write("""/*
+ * testapi.c: libxml2 API tester program.
+ *
+ * Automatically generated by gentest.py from libxml2-api.xml
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#include <stdio.h>
+#include <libxml/xmlerror.h>
+
+static int testlibxml2(void);
+
+static int generic_errors = 0;
+static int call_tests = 0;
+
+static void
+structured_errors(void *userData ATTRIBUTE_UNUSED,
+ xmlErrorPtr error ATTRIBUTE_UNUSED) {
+ generic_errors++;
+}
+
+int main(void) {
+ int ret;
+ int blocks, mem;
+
+ LIBXML_TEST_VERSION
+
+ xmlSetStructuredErrorFunc(NULL, structured_errors);
+
+ ret = testlibxml2();
+
+ xmlCleanupParser();
+ blocks = xmlMemBlocks();
+ mem = xmlMemUsed();
+ if ((blocks != 0) || (mem != 0)) {
+ printf("testapi leaked %d bytes in %d blocks\\n", mem, blocks);
+ }
+ xmlMemoryDump();
+
+ return (ret != 0);
+}
+
+""");
+
+#
+# Load the interfaces
+#
+for file in headers:
+ name = file.xpathEval('string(@name)')
+ if (name == None) or (name == ''):
+ continue
+
+ #
+ # do not test deprecated APIs
+ #
+ desc = file.xpathEval('string(description)')
+ if string.find(desc, 'DEPRECATED') != -1:
+ print "Skipping deprecated interface %s" % name
+ continue;
+
+ #
+ # Some module may be skipped because they don't really consists
+ # of user callable APIs
+ #
+ if is_skipped_module(name):
+ continue
+
+ test.write("#include <libxml/%s.h>\n" % name)
+ modules.append(name)
+
+#
+# Generate the callers signatures
+#
+for module in modules:
+ test.write("static int test_%s(void);\n" % module);
+
+#
+# Provide the type generators and destructors for the parameters
+#
+
+def type_convert(str, name, info, module, function):
+ res = string.replace(str, " *", "_ptr")
+ res = string.replace(res, " ", "_")
+ if res == 'const_char_ptr':
+ if string.find(name, "file") != -1 or \
+ string.find(name, "uri") != -1 or \
+ string.find(name, "URI") != -1 or \
+ string.find(info, "filename") != -1 or \
+ string.find(info, "URI") != -1 or \
+ string.find(info, "URL") != -1:
+ if string.find(function, "Save") != -1:
+ return('fileoutput')
+ return('filepath')
+ if res == 'void_ptr':
+ if module == 'nanoftp' and name == 'ctx':
+ return('xmlNanoFTPCtxtPtr')
+ if module == 'nanohttp' and name == 'ctx':
+ return('xmlNanoHTTPCtxtPtr')
+
+ return res
+
+known_param_types = [ "int", "const_char_ptr", "const_xmlChar_ptr",
+ "xmlParserCtxtPtr", "xmlDocPtr", "filepath", "fileoutput" ];
+
+def is_known_param_type(name):
+ for type in known_param_types:
+ if type == name:
+ return 1
+ return 0
+
+test.write("""
+#define gen_nb_int 4
+
+static int gen_int(int no) {
+ if (no == 0) return(0);
+ if (no == 1) return(1);
+ if (no == 2) return(122);
+ return(-1);
+}
+
+static void des_int(int no ATTRIBUTE_UNUSED, int val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_const_char_ptr 4
+
+static const char *gen_const_char_ptr(int no) {
+ if (no == 0) return("foo");
+ if (no == 1) return("<foo/>");
+ if (no == 2) return("test/ent2");
+ return(NULL);
+}
+static void des_const_char_ptr(int no ATTRIBUTE_UNUSED, const char *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_const_xmlChar_ptr 5
+
+static const xmlChar *gen_const_xmlChar_ptr(int no) {
+ if (no == 0) return((const xmlChar *) "foo");
+ if (no == 1) return((const xmlChar *) "<foo/>");
+ if (no == 2) return((const xmlChar *) "nøne");
+ if (no == 3) return((const xmlChar *) " 2ab ");
+ return(NULL);
+}
+static void des_const_xmlChar_ptr(int no ATTRIBUTE_UNUSED, const xmlChar *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_filepath 8
+
+static const char *gen_filepath(int no) {
+ if (no == 0) return("missing.xml");
+ if (no == 1) return("<foo/>");
+ if (no == 2) return("test/ent2");
+ if (no == 3) return("test/valid/REC-xml-19980210.xml");
+ if (no == 4) return("test/valid/xhtml1-strict.dtd");
+ if (no == 5) return("http://missing.example.org/");
+ if (no == 6) return("http://missing. example.org/");
+ return(NULL);
+}
+static void des_filepath(int no ATTRIBUTE_UNUSED, const char *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_fileoutput 6
+
+static const char *gen_fileoutput(int no) {
+ if (no == 0) return("/missing.xml");
+ if (no == 1) return("<foo/>");
+ if (no == 2) return("ftp://missing.example.org/foo");
+ if (no == 3) return("http://missing.example.org/");
+ if (no == 4) return("http://missing. example.org/");
+ return(NULL);
+}
+static void des_fileoutput(int no ATTRIBUTE_UNUSED, const char *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_xmlParserCtxtPtr 2
+static xmlParserCtxtPtr gen_xmlParserCtxtPtr(int no) {
+ if (no == 0) return(xmlNewParserCtxt());
+ return(NULL);
+}
+static void des_xmlParserCtxtPtr(int no ATTRIBUTE_UNUSED, xmlParserCtxtPtr val) {
+ if (val != NULL)
+ xmlFreeParserCtxt(val);
+}
+
+#define gen_nb_xmlDocPtr 2
+static xmlDocPtr gen_xmlDocPtr(int no) {
+ if (no == 0) return(xmlNewDoc(BAD_CAST "1.0"));
+ return(NULL);
+}
+static void des_xmlDocPtr(int no ATTRIBUTE_UNUSED, xmlDocPtr val) {
+ if (val != NULL)
+ xmlFreeDoc(val);
+}
+
+""");
+
+#
+# Provide the type destructors for the return values
+#
+
+known_return_types = [ "int", "const_char_ptr", "xmlDocPtr", "xmlNodePtr" ];
+
+def is_known_return_type(name):
+ for type in known_return_types:
+ if type == name:
+ return 1
+ return 0
+
+test.write("""
+static void desret_int(int val ATTRIBUTE_UNUSED) {
+}
+static void desret_const_char_ptr(const char *val ATTRIBUTE_UNUSED) {
+}
+static void desret_xmlDocPtr(xmlDocPtr val) {
+ xmlFreeDoc(val);
+}
+static void desret_xmlNodePtr(xmlNodePtr val) {
+ xmlUnlinkNode(val);
+ xmlFreeNode(val);
+}
+""");
+
+#
+# Generate the top caller
+#
+
+test.write("""
+/**
+ * testlibxml2:
+ *
+ * Main entry point of the tester for the full libxml2 module,
+ * it calls all the tester entry point for each module.
+ *
+ * Returns the number of error found
+ */
+static int
+testlibxml2(void)
+{
+ int ret = 0;
+
+""")
+
+for module in modules:
+ test.write(" ret += test_%s();\n" % module)
+
+test.write("""
+ printf("Total: %d tests, %d errors\\n", call_tests, ret);
+ return(ret);
+}
+
+""")
+
+#
+# How to handle a function
+#
+nb_tests = 0
+
+def generate_test(module, node):
+ global test
+ global nb_tests
+ nb_cond = 0
+ no_gen = 0
+
+ name = node.xpathEval('string(@name)')
+ if is_skipped_function(name):
+ return
+
+ test.write("""
+static int
+test_%s(void) {
+ int ret = 0;
+
+""" % (name))
+
+ #
+ # check we know how to handle the args and return values
+ # and store the informations for the generation
+ #
+ try:
+ args = node.xpathEval("arg")
+ except:
+ args = []
+ t_args = []
+ for arg in args:
+ rtype = arg.xpathEval("string(@type)")
+ if rtype == 'void':
+ break;
+ info = arg.xpathEval("string(@info)")
+ nam = arg.xpathEval("string(@name)")
+ type = type_convert(rtype, nam, info, module, name)
+ if is_known_param_type(type) == 0:
+ add_missing_type(type, name);
+ no_gen = 1
+ t_args.append((nam, type, rtype, info))
+
+ try:
+ rets = node.xpathEval("return")
+ except:
+ rets = []
+ t_ret = None
+ for ret in rets:
+ rtype = ret.xpathEval("string(@type)")
+ info = ret.xpathEval("string(@info)")
+ type = type_convert(rtype, 'return', info, module, name)
+ if rtype == 'void':
+ break
+ if is_known_return_type(type) == 0:
+ add_missing_type(type, name);
+ no_gen = 1
+ t_ret = (type, rtype, info)
+ break
+
+ if no_gen == 1:
+ test.write("""
+ /* missing type support */
+ return(ret);
+}
+
+""")
+ return
+
+ try:
+ conds = node.xpathEval("cond")
+ for cond in conds:
+ test.write("#ifdef %s\n" % (cond.get_content()))
+ nb_cond = nb_cond + 1
+ except:
+ pass
+
+ # Declare the memory usage counter
+ no_mem = is_skipped_memcheck(name)
+ if no_mem == 0:
+ test.write(" int mem_base;\n");
+
+ # Declare the return value
+ if t_ret != None:
+ test.write(" %s ret_val;\n" % (t_ret[1]))
+
+ # Declare the arguments
+ for arg in t_args:
+ (nam, type, rtype, info) = arg;
+ # add declaration
+ test.write(" %s %s; /* %s */\n" % (rtype, nam, info))
+ test.write(" int n_%s;\n" % (nam))
+ test.write("\n")
+
+ # Cascade loop on of each argument list of values
+ for arg in t_args:
+ (nam, type, rtype, info) = arg;
+ #
+ test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
+ nam, nam, type, nam))
+
+ # log the memory usage
+ if no_mem == 0:
+ test.write(" mem_base = xmlMemBlocks();\n");
+
+ # prepare the call
+ for arg in t_args:
+ (nam, type, rtype, info) = arg;
+ #
+ test.write(" %s = gen_%s(n_%s);\n" % (nam, type, nam))
+
+ # do the call, and clanup the result
+ if t_ret != None:
+ test.write("\n ret_val = %s(" % (name))
+ need = 0
+ for arg in t_args:
+ (nam, type, rtype, info) = arg
+ if need:
+ test.write(", ")
+ else:
+ need = 1
+ test.write("%s" % nam);
+ test.write(");\n desret_%s(ret_val);\n" % t_ret[0])
+ else:
+ test.write("\n %s(" % (name));
+ need = 0;
+ for arg in t_args:
+ (nam, type, rtype, info) = arg;
+ if need:
+ test.write(", ")
+ else:
+ need = 1
+ test.write("%s" % nam)
+ test.write(");\n")
+ test.write(" call_tests++;\n");
+
+ # Free the arguments
+ for arg in t_args:
+ (nam, type, rtype, info) = arg;
+ #
+ test.write(" des_%s(n_%s, %s);\n" % (type, nam, nam))
+
+ test.write(" xmlResetLastError();\n");
+ # Check the memory usage
+ if no_mem == 0:
+ test.write(""" if (mem_base != xmlMemBlocks()) {
+ printf("Leak of %%d blocks found in %s\\n",
+ xmlMemBlocks() - mem_base);
+ ret++;
+ }
+""" % (name));
+
+ for arg in t_args:
+ test.write(" }\n")
+
+ #
+ # end of conditional
+ #
+ while nb_cond > 0:
+ test.write("#endif\n")
+ nb_cond = nb_cond -1
+
+ nb_tests = nb_tests + 1;
+
+ test.write("""
+ return(ret);
+}
+
+""")
+
+#
+# Generate all module callers
+#
+for module in modules:
+ # gather all the functions exported by that module
+ try:
+ functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
+ except:
+ print "Failed to gather functions from module %s" % (module)
+ continue;
+
+ # iterate over all functions in the module generating the test
+ for function in functions:
+ generate_test(module, function);
+
+ # header
+ test.write("""static int
+test_%s(void) {
+ int ret = 0;
+
+ printf("Testing %s ...\\n");
+""" % (module, module))
+
+ # iterate over all functions in the module generating the call
+ for function in functions:
+ name = function.xpathEval('string(@name)')
+ if is_skipped_function(name):
+ continue
+ test.write(" ret += test_%s();\n" % (name))
+
+ # footer
+ test.write("""
+ if (ret != 0)
+ printf("Module %s: %%d errors\\n", ret);
+ return(ret);
+}
+""" % (module))
+
+print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
+nr = 0
+miss = 'none'
+for missing in missing_types.keys():
+ n = len(missing_types[missing])
+ if n > nr:
+ miss = missing
+ nr = n
+
+if nr > 0:
+ print "most needed type support: %s %d times" % (miss, nr)
+
+
diff --git a/include/libxml/xmlmemory.h b/include/libxml/xmlmemory.h
index 0e6a7672..235721ce 100644
--- a/include/libxml/xmlmemory.h
+++ b/include/libxml/xmlmemory.h
@@ -139,6 +139,8 @@ XMLPUBFUN void XMLCALL
*/
XMLPUBFUN int XMLCALL
xmlMemUsed (void);
+XMLPUBFUN int XMLCALL
+ xmlMemBlocks (void);
XMLPUBFUN void XMLCALL
xmlMemDisplay (FILE *fp);
XMLPUBFUN void XMLCALL
diff --git a/nanoftp.c b/nanoftp.c
index 16e6242f..30d143ff 100644
--- a/nanoftp.c
+++ b/nanoftp.c
@@ -260,12 +260,18 @@ xmlNanoFTPCleanup(void) {
void
xmlNanoFTPProxy(const char *host, int port, const char *user,
const char *passwd, int type) {
- if (proxy != NULL)
+ if (proxy != NULL) {
xmlFree(proxy);
- if (proxyUser != NULL)
+ proxy = NULL;
+ }
+ if (proxyUser != NULL) {
xmlFree(proxyUser);
- if (proxyPasswd != NULL)
+ proxyUser = NULL;
+ }
+ if (proxyPasswd != NULL) {
xmlFree(proxyPasswd);
+ proxyPasswd = NULL;
+ }
if (host)
proxy = xmlMemStrdup(host);
if (user)
diff --git a/parser.c b/parser.c
index 8a03b0cc..7a51c051 100644
--- a/parser.c
+++ b/parser.c
@@ -949,6 +949,8 @@ mem_error:
int
inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value)
{
+ if ((ctxt == NULL) || (value == NULL))
+ return(0);
if (ctxt->inputNr >= ctxt->inputMax) {
ctxt->inputMax *= 2;
ctxt->inputTab =
@@ -977,6 +979,8 @@ inputPop(xmlParserCtxtPtr ctxt)
{
xmlParserInputPtr ret;
+ if (ctxt == NULL)
+ return(NULL);
if (ctxt->inputNr <= 0)
return (0);
ctxt->inputNr--;
@@ -8541,6 +8545,9 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) {
xmlInitParser();
+ if ((ctxt == NULL) || (ctxt->input == NULL))
+ return(-1);
+
GROW;
/*
@@ -8700,6 +8707,9 @@ xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) {
xmlChar start[4];
xmlCharEncoding enc;
+ if ((ctxt == NULL) || (ctxt->input == NULL))
+ return(-1);
+
xmlDefaultSAXHandlerInit();
xmlDetectSAX2(ctxt);
@@ -8942,6 +8952,9 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
xmlChar cur, next;
const xmlChar *lastlt, *lastgt;
+ if (ctxt->input == NULL)
+ return(0);
+
#ifdef DEBUG_PUSH
switch (ctxt->instate) {
case XML_PARSER_EOF:
@@ -9801,6 +9814,8 @@ done:
int
xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
int terminate) {
+ if (ctxt == NULL)
+ return(XML_ERR_INTERNAL_ERROR);
if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
return(ctxt->errNo);
if (ctxt->instate == XML_PARSER_START)
@@ -9849,13 +9864,16 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
/*
* Check for termination
*/
- int avail = 0;
+ int avail = 0;
+
+ if (ctxt->input != NULL) {
if (ctxt->input->buf == NULL)
- avail = ctxt->input->length -
- (ctxt->input->cur - ctxt->input->base);
- else
- avail = ctxt->input->buf->buffer->use -
- (ctxt->input->cur - ctxt->input->base);
+ avail = ctxt->input->length -
+ (ctxt->input->cur - ctxt->input->base);
+ else
+ avail = ctxt->input->buf->buffer->use -
+ (ctxt->input->cur - ctxt->input->base);
+ }
if ((ctxt->instate != XML_PARSER_EOF) &&
(ctxt->instate != XML_PARSER_EPILOG)) {
@@ -11638,10 +11656,13 @@ xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer,
{
xmlParserInputPtr input;
+ if ((ctxt == NULL) || (buffer == NULL))
+ return;
+
input = xmlNewInputStream(ctxt);
if (input == NULL) {
xmlErrMemory(NULL, "parsing new buffer: out of memory\n");
- xmlFree(ctxt);
+ xmlClearParserCtxt(ctxt);
return;
}
@@ -12094,6 +12115,9 @@ xmlCleanupParser(void) {
#ifdef LIBXML_OUTPUT_ENABLED
xmlCleanupOutputCallbacks();
#endif
+#ifdef LIBXML_SCHEMAS_ENABLED
+ xmlSchemaCleanupTypes();
+#endif
xmlCleanupGlobals();
xmlResetLastError();
xmlCleanupThreads(); /* must be last if called not from the main thread */
@@ -12129,7 +12153,12 @@ void
xmlCtxtReset(xmlParserCtxtPtr ctxt)
{
xmlParserInputPtr input;
- xmlDictPtr dict = ctxt->dict;
+ xmlDictPtr dict;
+
+ if (ctxt == NULL)
+ return;
+
+ dict = ctxt->dict;
while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
xmlFreeInputStream(input);
@@ -12325,6 +12354,8 @@ xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk,
int
xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options)
{
+ if (ctxt == NULL)
+ return(-1);
if (options & XML_PARSE_RECOVER) {
ctxt->recovery = 1;
options -= XML_PARSE_RECOVER;
diff --git a/parserInternals.c b/parserInternals.c
index 42db4115..c338a53f 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -1520,12 +1520,14 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
xmlDefaultSAXHandlerInit();
- ctxt->dict = xmlDictCreate();
+ if (ctxt->dict == NULL)
+ ctxt->dict = xmlDictCreate();
if (ctxt->dict == NULL) {
xmlErrMemory(NULL, "cannot initialize parser context\n");
return(-1);
}
- ctxt->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
+ if (ctxt->sax == NULL)
+ ctxt->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
if (ctxt->sax == NULL) {
xmlErrMemory(NULL, "cannot initialize parser context\n");
return(-1);
@@ -1536,8 +1538,11 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->maxatts = 0;
ctxt->atts = NULL;
/* Allocate the Input stack */
- ctxt->inputTab = (xmlParserInputPtr *)
- xmlMalloc(5 * sizeof(xmlParserInputPtr));
+ if (ctxt->inputTab == NULL) {
+ ctxt->inputTab = (xmlParserInputPtr *)
+ xmlMalloc(5 * sizeof(xmlParserInputPtr));
+ ctxt->inputMax = 5;
+ }
if (ctxt->inputTab == NULL) {
xmlErrMemory(NULL, "cannot initialize parser context\n");
ctxt->inputNr = 0;
@@ -1546,7 +1551,6 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
return(-1);
}
ctxt->inputNr = 0;
- ctxt->inputMax = 5;
ctxt->input = NULL;
ctxt->version = NULL;
@@ -1561,7 +1565,10 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
ctxt->directory = NULL;
/* Allocate the Node stack */
- ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
+ if (ctxt->nodeTab == NULL) {
+ ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
+ ctxt->nodeMax = 10;
+ }
if (ctxt->nodeTab == NULL) {
xmlErrMemory(NULL, "cannot initialize parser context\n");
ctxt->nodeNr = 0;
@@ -1573,11 +1580,13 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
return(-1);
}
ctxt->nodeNr = 0;
- ctxt->nodeMax = 10;
ctxt->node = NULL;
/* Allocate the Name stack */
- ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
+ if (ctxt->nameTab == NULL) {
+ ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
+ ctxt->nameMax = 10;
+ }
if (ctxt->nameTab == NULL) {
xmlErrMemory(NULL, "cannot initialize parser context\n");
ctxt->nodeNr = 0;
@@ -1592,11 +1601,13 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
return(-1);
}
ctxt->nameNr = 0;
- ctxt->nameMax = 10;
ctxt->name = NULL;
/* Allocate the space stack */
- ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int));
+ if (ctxt->spaceTab == NULL) {
+ ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int));
+ ctxt->spaceMax = 10;
+ }
if (ctxt->spaceTab == NULL) {
xmlErrMemory(NULL, "cannot initialize parser context\n");
ctxt->nodeNr = 0;
@@ -1784,7 +1795,7 @@ xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
if (ctxt==NULL)
return;
xmlClearNodeInfoSeq(&ctxt->node_seq);
- xmlInitParserCtxt(ctxt);
+ xmlCtxtReset(ctxt);
}
/**
diff --git a/test/slashdot16.xml b/test/slashdot16.xml
new file mode 100644
index 00000000..f6a7f2a5
--- /dev/null
+++ b/test/slashdot16.xml
Binary files differ
diff --git a/tree.c b/tree.c
index 9de498d4..1eea2688 100644
--- a/tree.c
+++ b/tree.c
@@ -345,6 +345,9 @@ xmlValidateNCName(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
+ if (value == NULL)
+ return(-1);
+
/*
* First quick algorithm for ASCII range
*/
@@ -416,6 +419,8 @@ xmlValidateQName(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
+ if (value == NULL)
+ return(-1);
/*
* First quick algorithm for ASCII range
*/
@@ -512,6 +517,8 @@ xmlValidateName(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
+ if (value == NULL)
+ return(-1);
/*
* First quick algorithm for ASCII range
*/
@@ -579,6 +586,8 @@ xmlValidateNMToken(const xmlChar *value, int space) {
const xmlChar *cur = value;
int c,l;
+ if (value == NULL)
+ return(-1);
/*
* First quick algorithm for ASCII range
*/
@@ -2503,6 +2512,9 @@ xmlNodePtr
xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
xmlNodePtr cur;
+ if (name == NULL)
+ return(NULL);
+
/*
* Allocate a new node and fill the fields.
*/
@@ -2544,6 +2556,9 @@ xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
xmlNodePtr cur;
xmlEntityPtr ent;
+ if (name == NULL)
+ return(NULL);
+
/*
* Allocate a new node and fill the fields.
*/
diff --git a/xmlIO.c b/xmlIO.c
index 198fb15a..f33d3552 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -551,6 +551,9 @@ xmlCleanupOutputCallbacks(void)
int
xmlCheckFilename (const char *path)
{
+ if (path == NULL)
+ return(0);
+
#ifdef HAVE_STAT
struct stat stat_buffer;
diff --git a/xmlmemory.c b/xmlmemory.c
index 821e3b94..69de28d7 100644
--- a/xmlmemory.c
+++ b/xmlmemory.c
@@ -50,6 +50,7 @@
static int xmlMemInitialized = 0;
static unsigned long debugMemSize = 0;
+static unsigned long debugMemBlocks = 0;
static unsigned long debugMaxMemSize = 0;
static xmlMutexPtr xmlMemMutex = NULL;
@@ -186,6 +187,7 @@ xmlMallocLoc(size_t size, const char * file, int line)
xmlMutexLock(xmlMemMutex);
p->mh_number = ++block;
debugMemSize += size;
+ debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
@@ -253,6 +255,7 @@ xmlMallocAtomicLoc(size_t size, const char * file, int line)
xmlMutexLock(xmlMemMutex);
p->mh_number = ++block;
debugMemSize += size;
+ debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
@@ -329,6 +332,7 @@ xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
p->mh_tag = ~MEMTAG;
xmlMutexLock(xmlMemMutex);
debugMemSize -= p->mh_size;
+ debugMemBlocks--;
#ifdef DEBUG_MEMORY
oldsize = p->mh_size;
#endif
@@ -355,6 +359,7 @@ xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
p->mh_line = line;
xmlMutexLock(xmlMemMutex);
debugMemSize += size;
+ debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
@@ -428,6 +433,7 @@ xmlMemFree(void *ptr)
memset(target, -1, p->mh_size);
xmlMutexLock(xmlMemMutex);
debugMemSize -= p->mh_size;
+ debugMemBlocks--;
#ifdef DEBUG_MEMORY
size = p->mh_size;
#endif
@@ -487,6 +493,7 @@ xmlMemStrdupLoc(const char *str, const char *file, int line)
xmlMutexLock(xmlMemMutex);
p->mh_number = ++block;
debugMemSize += size;
+ debugMemBlocks++;
if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
#ifdef MEM_LIST
debugmem_list_add(p);
@@ -543,6 +550,19 @@ xmlMemUsed(void) {
return(debugMemSize);
}
+/**
+ * xmlMemBlocks:
+ *
+ * Provides the number of memory areas currently allocated
+ *
+ * Returns an int representing the number of blocks
+ */
+
+int
+xmlMemBlocks(void) {
+ return(debugMemBlocks);
+}
+
#ifdef MEM_LIST
/**
* xmlMemContentShow:
diff --git a/xmlstring.c b/xmlstring.c
index af4e5c81..15ca76c8 100644
--- a/xmlstring.c
+++ b/xmlstring.c
@@ -807,7 +807,6 @@ xmlCheckUTF8(const unsigned char *utf)
*
* Returns the storage size of
* the first 'len' characters of ARRAY
- *
*/
int
@@ -815,6 +814,9 @@ xmlUTF8Strsize(const xmlChar *utf, int len) {
const xmlChar *ptr=utf;
xmlChar ch;
+ if (utf == NULL)
+ return(0);
+
if (len <= 0)
return(0);