1 /* 2 * testOOM.c: Test out-of-memory handling 3 * 4 * See Copyright for the status of this software. 5 * 6 * hp (at) 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 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 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 } 378