further fixes for out of memory condition, mostly from Olivier Andrieu.

* SAX2.c, tree.c, uri.c, xmlIO.c, xmlreader.c: further
  fixes for out of memory condition, mostly from Olivier
  Andrieu.
* testOOM.c: some further improvement by Olivier, with
  a further small enhancement for easier debugging.
diff --git a/ChangeLog b/ChangeLog
index 6b954b5..b227503 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Thu Jul 29 00:05:58 PDT 2004 William Brack <wbrack@mmm.com.hk>
+
+	* SAX2.c, tree.c, uri.c, xmlIO.c, xmlreader.c: further
+	  fixes for out of memory condition, mostly from Olivier
+	  Andrieu.
+	* testOOM.c: some further improvement by Olivier, with
+	  a further small enhancement for easier debugging.
+
 Tue Jul 27 00:34:07 PDT 2004 William Brack <wbrack@mmm.com.hk>
 
 	* SAX2.c, error.c, parser.c, tree.c, xmlreader.c:
diff --git a/SAX2.c b/SAX2.c
index 23ed1a1..b92b1c7 100644
--- a/SAX2.c
+++ b/SAX2.c
@@ -44,6 +44,20 @@
 	    "Unimplemented block at %s:%d\n",				\
             __FILE__, __LINE__);
 
+/*
+ * xmlSAX2ErrMemory:
+ * @ctxt:  an XML validation parser context
+ * @msg:   a string to accompany the error message
+ */
+static void
+xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, char *msg) {
+    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+        ctxt->sax->error(ctxt->userData, "%s: out of memory\n", msg);
+    ctxt->errNo = XML_ERR_NO_MEMORY;
+    ctxt->instate = XML_PARSER_EOF;
+    ctxt->disableSAX = 1;
+}
+
 /**
  * xmlValidError:
  * @ctxt:  an XML validation parser context
@@ -214,6 +228,8 @@
     }
     ctxt->myDoc->intSubset = 
 	xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
+    if (ctxt->myDoc->intSubset == NULL)
+        xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset");
 }
 
 /**
@@ -273,13 +289,7 @@
 	ctxt->inputTab = (xmlParserInputPtr *)
 	                 xmlMalloc(5 * sizeof(xmlParserInputPtr));
 	if (ctxt->inputTab == NULL) {
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		ctxt->sax->error(ctxt->userData, 
-		     "xmlSAX2ExternalSubset: out of memory\n");
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset");
 	    ctxt->input = oldinput;
 	    ctxt->inputNr = oldinputNr;
 	    ctxt->inputMax = oldinputMax;
@@ -816,12 +826,7 @@
 	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.xmlSAX2StartDocument(): out of memory\n");
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
 	    return;
 	}
 #else
@@ -841,12 +846,7 @@
 		doc->encoding = NULL;
 	    doc->standalone = ctxt->standalone;
 	} else {
-	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		ctxt->sax->error(ctxt->userData, 
-		     "SAX.xmlSAX2StartDocument(): out of memory\n");
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
 	    return;
 	}
 	if ((ctxt->dictNames) && (doc != NULL)) {
@@ -945,12 +945,7 @@
 	name = xmlStrdup(fullname);
     }
     if (name == NULL) {
-	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	    ctxt->sax->error(ctxt->userData, 
-		 "SAX.xmlSAX2StartElement(): out of memory\n");
-	ctxt->errNo = XML_ERR_NO_MEMORY;
-	ctxt->instate = XML_PARSER_EOF;
-	ctxt->disableSAX = 1;
+        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
 	if (ns != NULL)
 	    xmlFree(ns);
 	return;
@@ -1044,12 +1039,7 @@
 		                          0,0,0);
 	    ctxt->depth--;
 	    if (val == NULL) {
-		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		    ctxt->sax->error(ctxt->userData, 
-			 "SAX.xmlSAX2StartElement(): out of memory\n");
-		ctxt->errNo = XML_ERR_NO_MEMORY;
-		ctxt->instate = XML_PARSER_EOF;
-		ctxt->disableSAX = 1;
+	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
 	        xmlFree(ns);
 		if (name != NULL) 
 		    xmlFree(name);
@@ -1345,13 +1335,7 @@
 
                         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.xmlSAX2StartElement(): out of memory\n");
-			    ctxt->errNo = XML_ERR_NO_MEMORY;
-			    ctxt->instate = XML_PARSER_EOF;
-			    ctxt->disableSAX = 1;
+			    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
 			    return;
 			}
 
@@ -1446,9 +1430,7 @@
     if (ret == NULL) {
         if (prefix != NULL)
 	    xmlFree(prefix);
-	ctxt->errNo = XML_ERR_NO_MEMORY;
-	ctxt->instate = XML_PARSER_EOF;
-	ctxt->disableSAX = 1;
+	xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
         return;
     }
     if (ctxt->myDoc->children == NULL) {
@@ -1672,12 +1654,7 @@
 	ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
     }
     if (ret == NULL) {
-	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	    ctxt->sax->error(ctxt->userData, 
-		 "SAX.xmlSAX2Characters(): out of memory\n");
-	ctxt->errNo = XML_ERR_NO_MEMORY;
-	ctxt->instate = XML_PARSER_EOF;
-	ctxt->disableSAX = 1;
+        xmlErrMemory(ctxt, "xmlSAX2Characters");
 	return(NULL);
     }
     /*
@@ -1708,9 +1685,8 @@
     if (intern == NULL) {
 	ret->content = xmlStrndup(str, len);
 	if (ret->content == NULL) {
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlSAX2ErrMemory(ctxt, "xmlSAX2TextNode");
+	    xmlFree(ret);
 	    return(NULL);
 	}
     } else
@@ -1822,9 +1798,7 @@
 	else
 	    ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL);
 	if (ret == NULL) {
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlErrMemory(ctxt, "xmlSAX2AttributeNs");
 	    return;
 	}
     }
@@ -2042,9 +2016,7 @@
 	else {
 	    ret->name = xmlStrdup(localname);
 	    if (ret->name == NULL) {
-		ctxt->errNo = XML_ERR_NO_MEMORY;
-		ctxt->instate = XML_PARSER_EOF;
-		ctxt->disableSAX = 1;
+	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
 		return;
 	    }
 	}
@@ -2057,9 +2029,7 @@
 	else
 	    ret = xmlNewDocNode(ctxt->myDoc, NULL, localname, NULL);
 	if (ret == NULL) {
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
 	    return;
 	}
     }
@@ -2094,9 +2064,7 @@
 	    if ((URI != NULL) && (prefix == pref))
 		ret->ns = ns;
 	} else {
-	    ctxt->errNo = XML_ERR_NO_MEMORY;
-	    ctxt->instate = XML_PARSER_EOF;
-	    ctxt->disableSAX = 1;
+	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
 	    return;
 	}
 #ifdef LIBXML_VALID_ENABLED
@@ -2143,9 +2111,7 @@
 	if (ret->ns == NULL) {
 	    ns = xmlNewNs(ret, NULL, prefix);
 	    if (ns == NULL) {
-	        ctxt->errNo = XML_ERR_NO_MEMORY;
-		ctxt->instate = XML_PARSER_EOF;
-		ctxt->disableSAX = 1;
+	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
 		return;
 	    }
 	    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
@@ -2327,12 +2293,7 @@
 		size *= 2;
                 newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
 		if (newbuf == NULL) {
-		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-			ctxt->sax->error(ctxt->userData, 
-			     "SAX.xmlSAX2Characters(): out of memory\n");
-		    ctxt->errNo = XML_ERR_NO_MEMORY;
-		    ctxt->instate = XML_PARSER_EOF;
-		    ctxt->disableSAX = 1;
+		    xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
 		    return;
 		}
 		ctxt->nodemem = size;
@@ -2343,12 +2304,7 @@
 	    lastChild->content[ctxt->nodelen] = 0;
 	} else if (coalesceText) {
 	    if (xmlTextConcat(lastChild, ch, len)) {
-		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		    ctxt->sax->error(ctxt->userData, 
-			 "SAX.xmlSAX2Characters(): out of memory\n");
-		ctxt->errNo = XML_ERR_NO_MEMORY;
-		ctxt->instate = XML_PARSER_EOF;
-		ctxt->disableSAX = 1;
+		xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
 	    }
 	    if (ctxt->node->children != NULL) {
 		ctxt->nodelen = xmlStrlen(lastChild->content);
diff --git a/testOOM.c b/testOOM.c
index 7d9b411..717b67d 100644
--- a/testOOM.c
+++ b/testOOM.c
@@ -6,11 +6,6 @@
  * 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>
@@ -40,23 +35,140 @@
 #define FALSE (0)
 #endif
 
+#define EXIT_OOM 2
 
-int debug = 0;
-int dump = 0;
 int noent = 0;
 int count = 0;
 int valid = 0;
+int showErrs = 0;
+
+/*
+ * Since we are using the xmlTextReader functions, we set up
+ * strings for the element types to help in debugging any error
+ * output
+ */
+const char *elementNames[] = {
+    "XML_READER_TYPE_NONE",
+    "XML_READER_TYPE_ELEMENT",
+    "XML_READER_TYPE_ATTRIBUTE",
+    "XML_READER_TYPE_TEXT",
+    "XML_READER_TYPE_CDATA",
+    "XML_READER_TYPE_ENTITY_REFERENCE",
+    "XML_READER_TYPE_ENTITY",
+    "XML_READER_TYPE_PROCESSING_INSTRUCTION",
+    "XML_READER_TYPE_COMMENT",
+    "XML_READER_TYPE_DOCUMENT",
+    "XML_READER_TYPE_DOCUMENT_TYPE",
+    "XML_READER_TYPE_DOCUMENT_FRAGMENT",
+    "XML_READER_TYPE_NOTATION",
+    "XML_READER_TYPE_WHITESPACE",
+    "XML_READER_TYPE_SIGNIFICANT_WHITESPACE",
+    "XML_READER_TYPE_END_ELEMENT",
+    "XML_READER_TYPE_END_ENTITY",
+    "XML_READER_TYPE_XML_DECLARATION"};
+
+/* not using xmlBuff here because I don't want those 
+ * mallocs to interfere */
+struct buffer {
+    char *str;
+    size_t len;
+    size_t max;
+};
+
+static struct buffer *buffer_create (size_t init_len)
+{
+    struct buffer *b;
+    b = malloc (sizeof *b);
+    if (b == NULL)
+	exit (EXIT_OOM);
+    if (init_len) {
+	b->str = malloc (init_len);
+	if (b->str == NULL)
+	    exit (EXIT_OOM);
+    }
+    else
+	b->str = NULL;
+    b->len = 0;
+    b->max = init_len;
+    return b;
+}
+
+static void buffer_free (struct buffer *b)
+{
+    free (b->str);
+    free (b);
+}
+
+static size_t buffer_get_length (struct buffer *b)
+{
+    return b->len;
+}
+
+static void buffer_expand (struct buffer *b, size_t min)
+{
+    void *new_str;
+    size_t new_size = b->max ? b->max : 512;
+    while (new_size < b->len + min)
+	new_size *= 2;
+    if (new_size > b->max) {
+	new_str = realloc (b->str, new_size);
+	if (new_str == NULL)
+	    exit (EXIT_OOM);
+	b->str = new_str;
+	b->max = new_size;
+    }
+}
+
+static void buffer_add_char (struct buffer *b, char c)
+{
+    buffer_expand (b, 1);
+    b->str[b->len] = c;
+    b->len += 1;
+}
+
+static void buffer_add_string (struct buffer *b, const char *s)
+{
+    size_t size = strlen(s) + 1;
+    int ix;
+    for (ix=0; ix<size-1; ix++) {
+        if (s[ix] < 0x20)
+	    printf ("binary data [0x%02x]?\n", (unsigned char)s[ix]);
+    }
+    buffer_expand (b, size);
+    strcpy (b->str + b->len, s);
+    b->str[b->len+size-1] = '\n';	/* replace string term with newline */
+    b->len += size;
+}
+
+static int buffer_equal (struct buffer *b1, struct buffer *b2)
+{
+    return (b1->len == b2->len &&
+	    (b1->len == 0 || (memcmp (b1->str, b2->str, b1->len) == 0)));
+}
+
+static void buffer_dump (struct buffer *b, const char *fname)
+{
+    FILE *f = fopen (fname, "wb");
+    if (f != NULL) {
+	fwrite (b->str, 1, b->len, f);
+	fclose (f);
+    }
+}
+
 
 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");
+    printf("\t --show:  display the error messages encountered\n");
     exit(1);
 }
 static unsigned int elem, attrs, chars;
 
-static int processNode(xmlTextReaderPtr reader) {
+static int processNode (xmlTextReaderPtr reader, void *data)
+{
+    struct buffer *buff = data;
     int type;
 
     type = xmlTextReaderNodeType(reader);
@@ -74,72 +186,128 @@
 	}
     }
 
+    if (buff != NULL) {
+	int ret;
+	const char *s;
+
+	buffer_add_string (buff, elementNames[type]);
+
+	if (type == 1) {
+	    s = xmlTextReaderConstName (reader);
+	    if (s == NULL) return FALSE;
+	    buffer_add_string (buff, s);
+	    while ((ret = xmlTextReaderMoveToNextAttribute (reader)) == 1) {
+		s = xmlTextReaderConstName (reader);
+		if (s == NULL) return FALSE;
+		buffer_add_string (buff, s);
+		buffer_add_char (buff, '=');
+		s = xmlTextReaderConstValue (reader);
+		if (s == NULL) return FALSE;
+		buffer_add_string (buff, s);		
+	    }
+	    if (ret == -1) return FALSE;
+	}
+	else if (type == 3) {
+	    s = xmlTextReaderConstValue (reader);
+	    if (s == NULL) return FALSE;
+	    buffer_add_string (buff, s);
+	}
+    }
+
     return TRUE;
 }
 
 
 struct file_params {
-  const char *filename;
-  unsigned int elem, attrs, chars;
+    const char *filename;
+    struct buffer *verif_buff;
 };
 
-/* 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 void
+error_func (void *data, xmlErrorPtr err)
+{
+    int *e = data;
+    if (err->level == XML_ERR_ERROR ||
+        err->level == XML_ERR_FATAL)
+        *e = TRUE;
+    if (showErrs) {
+        printf("line %d: %s\n", err->line, err->message);
+    }
+}
+
 static int
 check_load_file_memory_func (void *data)
 {
      struct file_params *p = data;
+     struct buffer *b;
      xmlTextReaderPtr reader;
-     int ret, status;
+     int ret, status, first_run, error;
 
      if (count) {
-          elem = 0;
-          attrs = 0;
-          chars = 0;
+         elem = 0;
+         attrs = 0;
+         chars = 0;
      }
 
+     first_run = p->verif_buff == NULL;
      status = TRUE;
-     reader = xmlNewTextReaderFilename(p->filename);
+     error = FALSE;
+     if (first_run)
+	 b = buffer_create (0);
+     else
+	 b = buffer_create (buffer_get_length (p->verif_buff));
 
-     if (reader != NULL) {
-          if (valid) {
-               if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1) == -1)
-		    goto out;
-          }
-          
-          /*
-           * Process all nodes in sequence
-           */
-          while ((ret = xmlTextReaderRead(reader)) == 1) {
-	    if (!processNode(reader))
-	      goto out;
-          }
-	  if (ret == -1)
-	    goto out;
+     reader = xmlNewTextReaderFilename (p->filename);
+     if (reader == NULL)
+       goto out;
 
-          /*
-           * Done, cleanup and status
-           */
-	  if (count)
-	    {
-	      if (p->elem == (unsigned int)-1) {
-		p->elem = elem;
-		p->attrs = attrs;
-		p->chars = chars;
-	      }
-	      else {
-		status = (elem == p->elem && attrs == p->attrs && chars == p->chars);
-		fprintf (stderr, "# %s: %u elems, %u attrs, %u chars %s\n",
-			 p->filename, elem, attrs, chars,
-			 status ? "ok" : "wrong");
-	      }
-	    }
+     xmlTextReaderSetStructuredErrorHandler (reader, error_func, &error);
+
+     if (valid) {
+       if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1) == -1)
+	 goto out;
      }
+          
+     /*
+      * Process all nodes in sequence
+      */
+     while ((ret = xmlTextReaderRead(reader)) == 1) {
+	 if (!processNode(reader, b))
+	 goto out;
+     }
+     if (ret == -1)
+       goto out;
+
+     if (error) {
+	 fprintf (stdout, "error handler was called but parse completed successfully\n");
+	 return FALSE;
+     }
+
+     /*
+      * Done, cleanup and status
+      */
+     if (! first_run) {
+	 status = buffer_equal (p->verif_buff, b);
+	 if (! status) {
+	     buffer_dump (p->verif_buff, ".OOM.verif_buff");
+	     buffer_dump (b, ".OOM.buff");
+	 }
+     }
+     
+     if (count)
+       {
+	   fprintf (stdout, "# %s: %u elems, %u attrs, %u chars %s\n",
+		    p->filename, elem, attrs, chars,
+		    status ? "ok" : "wrong");
+       }
+
  out:
+     if (first_run)
+	 p->verif_buff = b;
+     else
+	 buffer_free (b);
      if (reader)
-       xmlFreeTextReader (reader);
+	 xmlFreeTextReader (reader);
      return status;
 }
 
@@ -157,19 +325,20 @@
                  test_malloc,
                  test_realloc,
                  test_strdup);
-    
+
+    xmlInitParser();
+
     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")))
+        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++;
+	else if ((!strcmp(argv[i], "-show")) ||
+		 (!strcmp(argv[i], "--show")))
+	    showErrs++;
     }
     if (noent != 0)
       xmlSubstituteEntitiesDefault(1);
@@ -177,27 +346,22 @@
 	if (argv[i][0] != '-') {
              struct file_params p;
 	     p.filename = argv[i];
-	     p.elem = -1;
+	     p.verif_buff = NULL;
 
-	     /* Run once to count */
-	     check_load_file_memory_func (&p);
-	     if (count) {
-	       fprintf (stderr, "# %s: %u elems, %u attrs, %u chars\n",
-			p.filename, p.elem, p.attrs, p.chars);
-	     }
              if (!test_oom_handling (check_load_file_memory_func,
                                      &p)) {
-                  fprintf (stderr, "Failed!\n");
-                  return (1);
+                  fprintf (stdout, "Failed!\n");
+                  return 1;
              }
 
+	     buffer_free (p.verif_buff);
              xmlCleanupParser();
 
              if (test_get_malloc_blocks_outstanding () > 0) {
-                  fprintf (stderr, "%d blocks leaked\n",
+                  fprintf (stdout, "%d blocks leaked\n",
                            test_get_malloc_blocks_outstanding ());
 		  xmlMemoryDump();
-                  return (1);
+                  return 1;
              }
              
 	    files ++;
@@ -205,5 +369,5 @@
     }
     xmlMemoryDump();
 
-    return(0);
+    return 0;
 }
diff --git a/tree.c b/tree.c
index fc22d52..a7109f9 100644
--- a/tree.c
+++ b/tree.c
@@ -6747,8 +6747,8 @@
 	if (rebuf != NULL) {
 	    memcpy(rebuf, buf->content, buf->use);
 	    xmlFree(buf->content);
+	    rebuf[buf->use] = 0;
 	}
-	rebuf[buf->use] = 0;
     }
     if (rebuf == NULL) {
 	xmlTreeErrMemory("growing buffer");
diff --git a/uri.c b/uri.c
index 31e51a3..d9dc760 100644
--- a/uri.c
+++ b/uri.c
@@ -2124,6 +2124,8 @@
     ix = xmlStrlen (uptr) + 1;
     val = (xmlChar *) xmlMalloc (ix + 3 * nbslash);
     if (val == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlBuildRelativeURI: out of memory\n");
 	goto done;
     }
     vptr = val;
@@ -2195,7 +2197,7 @@
     len = xmlStrlen(path);
     if ((len > 2) && IS_WINDOWS_PATH(path)) {
 	uri->scheme = xmlStrdup(BAD_CAST "file");
-	uri->path = xmlMallocAtomic(len + 2);
+	uri->path = xmlMallocAtomic(len + 2);	/* FIXME - check alloc! */
 	uri->path[0] = '/';
 	p = uri->path + 1;
 	strncpy(p, path, len + 1);
diff --git a/xmlIO.c b/xmlIO.c
index a51bf64..56d83c1 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -2180,6 +2180,9 @@
 	}
 #endif
     }
+    else
+      xmlInputCallbackTable[i].closecallback (context);
+
     return(ret);
 }
 
diff --git a/xmlreader.c b/xmlreader.c
index 923104c..8985bd9 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -1390,7 +1390,8 @@
         (reader->node->next == NULL) &&
         ((reader->node->type == XML_TEXT_NODE) ||
 	 (reader->node->type == XML_CDATA_SECTION_NODE))) {
-            xmlTextReaderExpand(reader);
+            if (xmlTextReaderExpand(reader) == NULL)
+	        return -1;
     }
 
 #ifdef LIBXML_XINCLUDE_ENABLED
@@ -1409,7 +1410,8 @@
 	/*
 	 * expand that node and process it
 	 */
-	xmlTextReaderExpand(reader);
+	if (xmlTextReaderExpand(reader) == NULL)
+	    return -1;
 	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
     }
     if (reader->node->type == XML_XINCLUDE_START) {
@@ -1878,6 +1880,7 @@
     ret->buffer = xmlBufferCreateSize(100);
     ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
     if (ret->sax == NULL) {
+	xmlBufferFree(ret->buffer);
 	xmlFree(ret);
         xmlGenericError(xmlGenericErrorContext,
 		"xmlNewTextReader : malloc failed\n");
@@ -1927,6 +1930,7 @@
     if (ret->ctxt == NULL) {
         xmlGenericError(xmlGenericErrorContext,
 		"xmlNewTextReader : malloc failed\n");
+	xmlBufferFree(ret->buffer);
 	xmlFree(ret->sax);
 	xmlFree(ret);
 	return(NULL);