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 40int error = FALSE; 41int errcount = 0; 42int noent = 0; 43int count = 0; 44int valid = 0; 45int 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 */ 52const 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 */ 74struct buffer { 75 char *str; 76 size_t len; 77 size_t max; 78}; 79 80static 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 98static void buffer_free (struct buffer *b) 99{ 100 free (b->str); 101 free (b); 102} 103 104static size_t buffer_get_length (struct buffer *b) 105{ 106 return b->len; 107} 108 109static 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 124static 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 131static 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 strcpy (b->str + b->len, s); 141 b->str[b->len+size-1] = '\n'; /* replace string term with newline */ 142 b->len += size; 143} 144 145static 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 151static 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 161static 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} 169static unsigned int elem, attrs, chars; 170 171static 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 223struct file_params { 224 const char *filename; 225 struct buffer *verif_buff; 226}; 227 228static void 229error_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 241static int 242check_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 318int 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} 378