diff options
author | Daniel Veillard <veillard@src.gnome.org> | 2004-11-02 14:52:23 +0000 |
---|---|---|
committer | Daniel Veillard <veillard@src.gnome.org> | 2004-11-02 14:52:23 +0000 |
commit | 36e5cd5064d3477a0500f6183d68b18b7493568a (patch) | |
tree | 95d13002a3bca1191e1328de0739dacbb15835ee | |
parent | 032268145fad72bbf00c944c1f6a067e5da4a1e0 (diff) | |
download | libxml2-36e5cd5064d3477a0500f6183d68b18b7493568a.tar.gz |
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-- | ChangeLog | 10 | ||||
-rw-r--r-- | HTMLtree.c | 6 | ||||
-rw-r--r-- | Makefile.am | 10 | ||||
-rw-r--r-- | SAX2.c | 4 | ||||
-rwxr-xr-x | gentest.py | 556 | ||||
-rw-r--r-- | include/libxml/xmlmemory.h | 2 | ||||
-rw-r--r-- | nanoftp.c | 12 | ||||
-rw-r--r-- | parser.c | 47 | ||||
-rw-r--r-- | parserInternals.c | 33 | ||||
-rw-r--r-- | test/slashdot16.xml | bin | 0 -> 10374 bytes | |||
-rw-r--r-- | tree.c | 15 | ||||
-rw-r--r-- | xmlIO.c | 3 | ||||
-rw-r--r-- | xmlmemory.c | 20 | ||||
-rw-r--r-- | xmlstring.c | 4 |
14 files changed, 697 insertions, 25 deletions
@@ -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 @@ -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) @@ -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 @@ -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) @@ -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 Binary files differnew file mode 100644 index 00000000..f6a7f2a5 --- /dev/null +++ b/test/slashdot16.xml @@ -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. */ @@ -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); |