/ libxml2 / testOOM.c
testOOM.c
  1  /*
  2   * testOOM.c: Test out-of-memory handling
  3   *
  4   * See Copyright for the status of this software.
  5   *
  6   * hp@redhat.com
  7   */
  8  
  9  #include "libxml.h"
 10  
 11  #include <string.h>
 12  #include <stdarg.h>
 13  
 14  #ifdef HAVE_SYS_TYPES_H
 15  #include <sys/types.h>
 16  #endif
 17  #ifdef HAVE_UNISTD_H
 18  #include <unistd.h>
 19  #endif
 20  #ifdef HAVE_STDLIB_H
 21  #include <stdlib.h>
 22  #endif
 23  #ifdef HAVE_STRING_H
 24  #include <string.h>
 25  #endif
 26  
 27  #include <libxml/xmlreader.h>
 28  
 29  #include "testOOMlib.h"
 30  
 31  #ifndef TRUE
 32  #define TRUE (1)
 33  #endif
 34  #ifndef FALSE
 35  #define FALSE (0)
 36  #endif
 37  
 38  #define EXIT_OOM 2
 39  
 40  int error = FALSE;
 41  int errcount = 0;
 42  int noent = 0;
 43  int count = 0;
 44  int valid = 0;
 45  int showErrs = 0;
 46  
 47  /*
 48   * Since we are using the xmlTextReader functions, we set up
 49   * strings for the element types to help in debugging any error
 50   * output
 51   */
 52  const char *elementNames[] = {
 53      "XML_READER_TYPE_NONE",
 54      "XML_READER_TYPE_ELEMENT",
 55      "XML_READER_TYPE_ATTRIBUTE",
 56      "XML_READER_TYPE_TEXT",
 57      "XML_READER_TYPE_CDATA",
 58      "XML_READER_TYPE_ENTITY_REFERENCE",
 59      "XML_READER_TYPE_ENTITY",
 60      "XML_READER_TYPE_PROCESSING_INSTRUCTION",
 61      "XML_READER_TYPE_COMMENT",
 62      "XML_READER_TYPE_DOCUMENT",
 63      "XML_READER_TYPE_DOCUMENT_TYPE",
 64      "XML_READER_TYPE_DOCUMENT_FRAGMENT",
 65      "XML_READER_TYPE_NOTATION",
 66      "XML_READER_TYPE_WHITESPACE",
 67      "XML_READER_TYPE_SIGNIFICANT_WHITESPACE",
 68      "XML_READER_TYPE_END_ELEMENT",
 69      "XML_READER_TYPE_END_ENTITY",
 70      "XML_READER_TYPE_XML_DECLARATION"};
 71  
 72  /* not using xmlBuff here because I don't want those
 73   * mallocs to interfere */
 74  struct buffer {
 75      char *str;
 76      size_t len;
 77      size_t max;
 78  };
 79  
 80  static struct buffer *buffer_create (size_t init_len)
 81  {
 82      struct buffer *b;
 83      b = malloc (sizeof *b);
 84      if (b == NULL)
 85  	exit (EXIT_OOM);
 86      if (init_len) {
 87  	b->str = malloc (init_len);
 88  	if (b->str == NULL)
 89  	    exit (EXIT_OOM);
 90      }
 91      else
 92  	b->str = NULL;
 93      b->len = 0;
 94      b->max = init_len;
 95      return b;
 96  }
 97  
 98  static void buffer_free (struct buffer *b)
 99  {
100      free (b->str);
101      free (b);
102  }
103  
104  static size_t buffer_get_length (struct buffer *b)
105  {
106      return b->len;
107  }
108  
109  static void buffer_expand (struct buffer *b, size_t min)
110  {
111      void *new_str;
112      size_t new_size = b->max ? b->max : 512;
113      while (new_size < b->len + min)
114  	new_size *= 2;
115      if (new_size > b->max) {
116  	new_str = realloc (b->str, new_size);
117  	if (new_str == NULL)
118  	    exit (EXIT_OOM);
119  	b->str = new_str;
120  	b->max = new_size;
121      }
122  }
123  
124  static void buffer_add_char (struct buffer *b, char c)
125  {
126      buffer_expand (b, 1);
127      b->str[b->len] = c;
128      b->len += 1;
129  }
130  
131  static void buffer_add_string (struct buffer *b, const char *s)
132  {
133      size_t size = strlen(s) + 1;
134      unsigned int ix;
135      for (ix=0; ix<size-1; ix++) {
136          if (s[ix] < 0x20)
137  	    printf ("binary data [0x%02x]?\n", (unsigned char)s[ix]);
138      }
139      buffer_expand (b, size);
140      strncpy(b->str + b->len, s, size);
141      b->str[b->len+size-1] = '\n';	/* replace string term with newline */
142      b->len += size;
143  }
144  
145  static int buffer_equal (struct buffer *b1, struct buffer *b2)
146  {
147      return (b1->len == b2->len &&
148  	    (b1->len == 0 || (memcmp (b1->str, b2->str, b1->len) == 0)));
149  }
150  
151  static void buffer_dump (struct buffer *b, const char *fname)
152  {
153      FILE *f = fopen (fname, "wb");
154      if (f != NULL) {
155  	fwrite (b->str, 1, b->len, f);
156  	fclose (f);
157      }
158  }
159  
160  
161  static void usage(const char *progname) {
162      printf("Usage : %s [options] XMLfiles ...\n", progname);
163      printf("\tParse the XML files using the xmlTextReader API\n");
164      printf("\t --count: count the number of attribute and elements\n");
165      printf("\t --valid: validate the document\n");
166      printf("\t --show:  display the error messages encountered\n");
167      exit(1);
168  }
169  static unsigned int elem, attrs, chars;
170  
171  static int processNode (xmlTextReaderPtr reader, void *data)
172  {
173      struct buffer *buff = data;
174      int type;
175  
176      type = xmlTextReaderNodeType(reader);
177      if (count) {
178  	if (type == 1) {
179  	    elem++;
180  	    attrs += xmlTextReaderAttributeCount(reader);
181  	} else if (type == 3) {
182  	  const xmlChar *txt;
183  	  txt = xmlTextReaderConstValue(reader);
184  	  if (txt != NULL)
185  	    chars += xmlStrlen (txt);
186  	  else
187  	    return FALSE;
188  	}
189      }
190  
191      if (buff != NULL) {
192  	int ret;
193  	const char *s;
194  
195  	buffer_add_string (buff, elementNames[type]);
196  
197  	if (type == 1) {
198  	    s = (const char *)xmlTextReaderConstName (reader);
199  	    if (s == NULL) return FALSE;
200  	    buffer_add_string (buff, s);
201  	    while ((ret = xmlTextReaderMoveToNextAttribute (reader)) == 1) {
202  		s = (const char *)xmlTextReaderConstName (reader);
203  		if (s == NULL) return FALSE;
204  		buffer_add_string (buff, s);
205  		buffer_add_char (buff, '=');
206  		s = (const char *)xmlTextReaderConstValue (reader);
207  		if (s == NULL) return FALSE;
208  		buffer_add_string (buff, s);
209  	    }
210  	    if (ret == -1) return FALSE;
211  	}
212  	else if (type == 3) {
213  	    s = (const char *)xmlTextReaderConstValue (reader);
214  	    if (s == NULL) return FALSE;
215  	    buffer_add_string (buff, s);
216  	}
217      }
218  
219      return TRUE;
220  }
221  
222  
223  struct file_params {
224      const char *filename;
225      struct buffer *verif_buff;
226  };
227  
228  static void
229  error_func (void *data ATTRIBUTE_UNUSED, xmlErrorPtr err)
230  {
231  
232      errcount++;
233      if (err->level == XML_ERR_ERROR ||
234          err->level == XML_ERR_FATAL)
235          error = TRUE;
236      if (showErrs) {
237          printf("%3d line %d: %s\n", error, err->line, err->message);
238      }
239  }
240  
241  static int
242  check_load_file_memory_func (void *data)
243  {
244       struct file_params *p = data;
245       struct buffer *b;
246       xmlTextReaderPtr reader;
247       int ret, status, first_run;
248  
249       if (count) {
250           elem = 0;
251           attrs = 0;
252           chars = 0;
253       }
254  
255       first_run = p->verif_buff == NULL;
256       status = TRUE;
257       error = FALSE;
258       if (first_run)
259  	 b = buffer_create (0);
260       else
261  	 b = buffer_create (buffer_get_length (p->verif_buff));
262  
263       reader = xmlNewTextReaderFilename (p->filename);
264       if (reader == NULL)
265         goto out;
266  
267       xmlTextReaderSetStructuredErrorHandler (reader, error_func, NULL);
268       xmlSetStructuredErrorFunc(NULL, error_func);
269  
270       if (valid) {
271         if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1) == -1)
272  	 goto out;
273       }
274  
275       /*
276        * Process all nodes in sequence
277        */
278       while ((ret = xmlTextReaderRead(reader)) == 1) {
279  	 if (!processNode(reader, b))
280  	 goto out;
281       }
282       if (ret == -1)
283         goto out;
284  
285       if (error) {
286  	 fprintf (stdout, "error handler was called but parse completed successfully (last error #%d)\n", errcount);
287  	 return FALSE;
288       }
289  
290       /*
291        * Done, cleanup and status
292        */
293       if (! first_run) {
294  	 status = buffer_equal (p->verif_buff, b);
295  	 if (! status) {
296  	     buffer_dump (p->verif_buff, ".OOM.verif_buff");
297  	     buffer_dump (b, ".OOM.buff");
298  	 }
299       }
300  
301       if (count)
302         {
303  	   fprintf (stdout, "# %s: %u elems, %u attrs, %u chars %s\n",
304  		    p->filename, elem, attrs, chars,
305  		    status ? "ok" : "wrong");
306         }
307  
308   out:
309       if (first_run)
310  	 p->verif_buff = b;
311       else
312  	 buffer_free (b);
313       if (reader)
314  	 xmlFreeTextReader (reader);
315       return status;
316  }
317  
318  int main(int argc, char **argv) {
319      int i;
320      int files = 0;
321  
322      if (argc <= 1) {
323  	usage(argv[0]);
324  	return(1);
325      }
326      LIBXML_TEST_VERSION;
327  
328      xmlMemSetup (test_free,
329                   test_malloc,
330                   test_realloc,
331                   test_strdup);
332  
333      xmlInitParser();
334  
335      for (i = 1; i < argc ; i++) {
336          if ((!strcmp(argv[i], "-count")) || (!strcmp(argv[i], "--count")))
337  	    count++;
338  	else if ((!strcmp(argv[i], "-valid")) || (!strcmp(argv[i], "--valid")))
339  	    valid++;
340  	else if ((!strcmp(argv[i], "-noent")) ||
341  	         (!strcmp(argv[i], "--noent")))
342  	    noent++;
343  	else if ((!strcmp(argv[i], "-show")) ||
344  		 (!strcmp(argv[i], "--show")))
345  	    showErrs++;
346      }
347      if (noent != 0)
348        xmlSubstituteEntitiesDefault(1);
349      for (i = 1; i < argc ; i++) {
350  	if (argv[i][0] != '-') {
351               struct file_params p;
352  	     p.filename = argv[i];
353  	     p.verif_buff = NULL;
354  
355               if (!test_oom_handling (check_load_file_memory_func,
356                                       &p)) {
357                    fprintf (stdout, "Failed!\n");
358                    return 1;
359               }
360  
361  	     buffer_free (p.verif_buff);
362               xmlCleanupParser();
363  
364               if (test_get_malloc_blocks_outstanding () > 0) {
365                    fprintf (stdout, "%d blocks leaked\n",
366                             test_get_malloc_blocks_outstanding ());
367  		  xmlMemoryDump();
368                    return 1;
369               }
370  
371  	    files ++;
372  	}
373      }
374      xmlMemoryDump();
375  
376      return 0;
377  }