OLD | NEW |
(Empty) | |
| 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 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 successf
ully (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 } |
OLD | NEW |