You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
8.3 KiB
377 lines
8.3 KiB
/* |
|
* testOOM.c: Test out-of-memory handling |
|
* |
|
* See Copyright for the status of this software. |
|
* |
|
* hp@redhat.com |
|
*/ |
|
|
|
#include "libxml.h" |
|
|
|
#include <string.h> |
|
#include <stdarg.h> |
|
|
|
#ifdef HAVE_SYS_TYPES_H |
|
#include <sys/types.h> |
|
#endif |
|
#ifdef HAVE_UNISTD_H |
|
#include <unistd.h> |
|
#endif |
|
#ifdef HAVE_STDLIB_H |
|
#include <stdlib.h> |
|
#endif |
|
#ifdef HAVE_STRING_H |
|
#include <string.h> |
|
#endif |
|
|
|
#include <libxml/xmlreader.h> |
|
|
|
#include "testOOMlib.h" |
|
|
|
#ifndef TRUE |
|
#define TRUE (1) |
|
#endif |
|
#ifndef FALSE |
|
#define FALSE (0) |
|
#endif |
|
|
|
#define EXIT_OOM 2 |
|
|
|
int error = FALSE; |
|
int errcount = 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; |
|
unsigned 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, void *data) |
|
{ |
|
struct buffer *buff = data; |
|
int type; |
|
|
|
type = xmlTextReaderNodeType(reader); |
|
if (count) { |
|
if (type == 1) { |
|
elem++; |
|
attrs += xmlTextReaderAttributeCount(reader); |
|
} else if (type == 3) { |
|
const xmlChar *txt; |
|
txt = xmlTextReaderConstValue(reader); |
|
if (txt != NULL) |
|
chars += xmlStrlen (txt); |
|
else |
|
return FALSE; |
|
} |
|
} |
|
|
|
if (buff != NULL) { |
|
int ret; |
|
const char *s; |
|
|
|
buffer_add_string (buff, elementNames[type]); |
|
|
|
if (type == 1) { |
|
s = (const char *)xmlTextReaderConstName (reader); |
|
if (s == NULL) return FALSE; |
|
buffer_add_string (buff, s); |
|
while ((ret = xmlTextReaderMoveToNextAttribute (reader)) == 1) { |
|
s = (const char *)xmlTextReaderConstName (reader); |
|
if (s == NULL) return FALSE; |
|
buffer_add_string (buff, s); |
|
buffer_add_char (buff, '='); |
|
s = (const char *)xmlTextReaderConstValue (reader); |
|
if (s == NULL) return FALSE; |
|
buffer_add_string (buff, s); |
|
} |
|
if (ret == -1) return FALSE; |
|
} |
|
else if (type == 3) { |
|
s = (const char *)xmlTextReaderConstValue (reader); |
|
if (s == NULL) return FALSE; |
|
buffer_add_string (buff, s); |
|
} |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
struct file_params { |
|
const char *filename; |
|
struct buffer *verif_buff; |
|
}; |
|
|
|
static void |
|
error_func (void *data ATTRIBUTE_UNUSED, xmlErrorPtr err) |
|
{ |
|
|
|
errcount++; |
|
if (err->level == XML_ERR_ERROR || |
|
err->level == XML_ERR_FATAL) |
|
error = TRUE; |
|
if (showErrs) { |
|
printf("%3d line %d: %s\n", error, 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, first_run; |
|
|
|
if (count) { |
|
elem = 0; |
|
attrs = 0; |
|
chars = 0; |
|
} |
|
|
|
first_run = p->verif_buff == NULL; |
|
status = TRUE; |
|
error = FALSE; |
|
if (first_run) |
|
b = buffer_create (0); |
|
else |
|
b = buffer_create (buffer_get_length (p->verif_buff)); |
|
|
|
reader = xmlNewTextReaderFilename (p->filename); |
|
if (reader == NULL) |
|
goto out; |
|
|
|
xmlTextReaderSetStructuredErrorHandler (reader, error_func, NULL); |
|
xmlSetStructuredErrorFunc(NULL, error_func); |
|
|
|
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 (last error #%d)\n", errcount); |
|
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); |
|
return status; |
|
} |
|
|
|
int main(int argc, char **argv) { |
|
int i; |
|
int files = 0; |
|
|
|
if (argc <= 1) { |
|
usage(argv[0]); |
|
return(1); |
|
} |
|
LIBXML_TEST_VERSION; |
|
|
|
xmlMemSetup (test_free, |
|
test_malloc, |
|
test_realloc, |
|
test_strdup); |
|
|
|
xmlInitParser(); |
|
|
|
for (i = 1; i < argc ; i++) { |
|
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); |
|
for (i = 1; i < argc ; i++) { |
|
if (argv[i][0] != '-') { |
|
struct file_params p; |
|
p.filename = argv[i]; |
|
p.verif_buff = NULL; |
|
|
|
if (!test_oom_handling (check_load_file_memory_func, |
|
&p)) { |
|
fprintf (stdout, "Failed!\n"); |
|
return 1; |
|
} |
|
|
|
buffer_free (p.verif_buff); |
|
xmlCleanupParser(); |
|
|
|
if (test_get_malloc_blocks_outstanding () > 0) { |
|
fprintf (stdout, "%d blocks leaked\n", |
|
test_get_malloc_blocks_outstanding ()); |
|
xmlMemoryDump(); |
|
return 1; |
|
} |
|
|
|
files ++; |
|
} |
|
} |
|
xmlMemoryDump(); |
|
|
|
return 0; |
|
}
|
|
|