blob: 717b67d974f09f9e98a1955313fda7156d494f0d [file] [log] [blame]
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001/*
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
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00009#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
William M. Brack42331a92004-07-29 07:07:16 +000038#define EXIT_OOM 2
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000039
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000040int noent = 0;
41int count = 0;
42int valid = 0;
William M. Brack42331a92004-07-29 07:07:16 +000043int showErrs = 0;
44
45/*
46 * Since we are using the xmlTextReader functions, we set up
47 * strings for the element types to help in debugging any error
48 * output
49 */
50const char *elementNames[] = {
51 "XML_READER_TYPE_NONE",
52 "XML_READER_TYPE_ELEMENT",
53 "XML_READER_TYPE_ATTRIBUTE",
54 "XML_READER_TYPE_TEXT",
55 "XML_READER_TYPE_CDATA",
56 "XML_READER_TYPE_ENTITY_REFERENCE",
57 "XML_READER_TYPE_ENTITY",
58 "XML_READER_TYPE_PROCESSING_INSTRUCTION",
59 "XML_READER_TYPE_COMMENT",
60 "XML_READER_TYPE_DOCUMENT",
61 "XML_READER_TYPE_DOCUMENT_TYPE",
62 "XML_READER_TYPE_DOCUMENT_FRAGMENT",
63 "XML_READER_TYPE_NOTATION",
64 "XML_READER_TYPE_WHITESPACE",
65 "XML_READER_TYPE_SIGNIFICANT_WHITESPACE",
66 "XML_READER_TYPE_END_ELEMENT",
67 "XML_READER_TYPE_END_ENTITY",
68 "XML_READER_TYPE_XML_DECLARATION"};
69
70/* not using xmlBuff here because I don't want those
71 * mallocs to interfere */
72struct buffer {
73 char *str;
74 size_t len;
75 size_t max;
76};
77
78static struct buffer *buffer_create (size_t init_len)
79{
80 struct buffer *b;
81 b = malloc (sizeof *b);
82 if (b == NULL)
83 exit (EXIT_OOM);
84 if (init_len) {
85 b->str = malloc (init_len);
86 if (b->str == NULL)
87 exit (EXIT_OOM);
88 }
89 else
90 b->str = NULL;
91 b->len = 0;
92 b->max = init_len;
93 return b;
94}
95
96static void buffer_free (struct buffer *b)
97{
98 free (b->str);
99 free (b);
100}
101
102static size_t buffer_get_length (struct buffer *b)
103{
104 return b->len;
105}
106
107static void buffer_expand (struct buffer *b, size_t min)
108{
109 void *new_str;
110 size_t new_size = b->max ? b->max : 512;
111 while (new_size < b->len + min)
112 new_size *= 2;
113 if (new_size > b->max) {
114 new_str = realloc (b->str, new_size);
115 if (new_str == NULL)
116 exit (EXIT_OOM);
117 b->str = new_str;
118 b->max = new_size;
119 }
120}
121
122static void buffer_add_char (struct buffer *b, char c)
123{
124 buffer_expand (b, 1);
125 b->str[b->len] = c;
126 b->len += 1;
127}
128
129static void buffer_add_string (struct buffer *b, const char *s)
130{
131 size_t size = strlen(s) + 1;
132 int ix;
133 for (ix=0; ix<size-1; ix++) {
134 if (s[ix] < 0x20)
135 printf ("binary data [0x%02x]?\n", (unsigned char)s[ix]);
136 }
137 buffer_expand (b, size);
138 strcpy (b->str + b->len, s);
139 b->str[b->len+size-1] = '\n'; /* replace string term with newline */
140 b->len += size;
141}
142
143static int buffer_equal (struct buffer *b1, struct buffer *b2)
144{
145 return (b1->len == b2->len &&
146 (b1->len == 0 || (memcmp (b1->str, b2->str, b1->len) == 0)));
147}
148
149static void buffer_dump (struct buffer *b, const char *fname)
150{
151 FILE *f = fopen (fname, "wb");
152 if (f != NULL) {
153 fwrite (b->str, 1, b->len, f);
154 fclose (f);
155 }
156}
157
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000158
159static void usage(const char *progname) {
160 printf("Usage : %s [options] XMLfiles ...\n", progname);
161 printf("\tParse the XML files using the xmlTextReader API\n");
162 printf("\t --count: count the number of attribute and elements\n");
163 printf("\t --valid: validate the document\n");
William M. Brack42331a92004-07-29 07:07:16 +0000164 printf("\t --show: display the error messages encountered\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000165 exit(1);
166}
William M. Brack9f797ab2004-07-28 07:40:12 +0000167static unsigned int elem, attrs, chars;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000168
William M. Brack42331a92004-07-29 07:07:16 +0000169static int processNode (xmlTextReaderPtr reader, void *data)
170{
171 struct buffer *buff = data;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000172 int type;
173
174 type = xmlTextReaderNodeType(reader);
175 if (count) {
176 if (type == 1) {
177 elem++;
178 attrs += xmlTextReaderAttributeCount(reader);
William M. Brack9f797ab2004-07-28 07:40:12 +0000179 } else if (type == 3) {
180 const xmlChar *txt;
181 txt = xmlTextReaderConstValue(reader);
182 if (txt != NULL)
183 chars += xmlStrlen (txt);
184 else
185 return FALSE;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000186 }
187 }
188
William M. Brack42331a92004-07-29 07:07:16 +0000189 if (buff != NULL) {
190 int ret;
191 const char *s;
192
193 buffer_add_string (buff, elementNames[type]);
194
195 if (type == 1) {
196 s = xmlTextReaderConstName (reader);
197 if (s == NULL) return FALSE;
198 buffer_add_string (buff, s);
199 while ((ret = xmlTextReaderMoveToNextAttribute (reader)) == 1) {
200 s = xmlTextReaderConstName (reader);
201 if (s == NULL) return FALSE;
202 buffer_add_string (buff, s);
203 buffer_add_char (buff, '=');
204 s = xmlTextReaderConstValue (reader);
205 if (s == NULL) return FALSE;
206 buffer_add_string (buff, s);
207 }
208 if (ret == -1) return FALSE;
209 }
210 else if (type == 3) {
211 s = xmlTextReaderConstValue (reader);
212 if (s == NULL) return FALSE;
213 buffer_add_string (buff, s);
214 }
215 }
216
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000217 return TRUE;
218}
219
William M. Brack9f797ab2004-07-28 07:40:12 +0000220
221struct file_params {
William M. Brack42331a92004-07-29 07:07:16 +0000222 const char *filename;
223 struct buffer *verif_buff;
William M. Brack9f797ab2004-07-28 07:40:12 +0000224};
225
William M. Brack42331a92004-07-29 07:07:16 +0000226static void
227error_func (void *data, xmlErrorPtr err)
228{
229 int *e = data;
230 if (err->level == XML_ERR_ERROR ||
231 err->level == XML_ERR_FATAL)
232 *e = TRUE;
233 if (showErrs) {
234 printf("line %d: %s\n", err->line, err->message);
235 }
236}
237
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000238static int
239check_load_file_memory_func (void *data)
240{
William M. Brack9f797ab2004-07-28 07:40:12 +0000241 struct file_params *p = data;
William M. Brack42331a92004-07-29 07:07:16 +0000242 struct buffer *b;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000243 xmlTextReaderPtr reader;
William M. Brack42331a92004-07-29 07:07:16 +0000244 int ret, status, first_run, error;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000245
246 if (count) {
William M. Brack42331a92004-07-29 07:07:16 +0000247 elem = 0;
248 attrs = 0;
249 chars = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000250 }
251
William M. Brack42331a92004-07-29 07:07:16 +0000252 first_run = p->verif_buff == NULL;
William M. Brack9f797ab2004-07-28 07:40:12 +0000253 status = TRUE;
William M. Brack42331a92004-07-29 07:07:16 +0000254 error = FALSE;
255 if (first_run)
256 b = buffer_create (0);
257 else
258 b = buffer_create (buffer_get_length (p->verif_buff));
William M. Brack9f797ab2004-07-28 07:40:12 +0000259
William M. Brack42331a92004-07-29 07:07:16 +0000260 reader = xmlNewTextReaderFilename (p->filename);
261 if (reader == NULL)
262 goto out;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000263
William M. Brack42331a92004-07-29 07:07:16 +0000264 xmlTextReaderSetStructuredErrorHandler (reader, error_func, &error);
265
266 if (valid) {
267 if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1) == -1)
268 goto out;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000269 }
William M. Brack42331a92004-07-29 07:07:16 +0000270
271 /*
272 * Process all nodes in sequence
273 */
274 while ((ret = xmlTextReaderRead(reader)) == 1) {
275 if (!processNode(reader, b))
276 goto out;
277 }
278 if (ret == -1)
279 goto out;
280
281 if (error) {
282 fprintf (stdout, "error handler was called but parse completed successfully\n");
283 return FALSE;
284 }
285
286 /*
287 * Done, cleanup and status
288 */
289 if (! first_run) {
290 status = buffer_equal (p->verif_buff, b);
291 if (! status) {
292 buffer_dump (p->verif_buff, ".OOM.verif_buff");
293 buffer_dump (b, ".OOM.buff");
294 }
295 }
296
297 if (count)
298 {
299 fprintf (stdout, "# %s: %u elems, %u attrs, %u chars %s\n",
300 p->filename, elem, attrs, chars,
301 status ? "ok" : "wrong");
302 }
303
William M. Brack9f797ab2004-07-28 07:40:12 +0000304 out:
William M. Brack42331a92004-07-29 07:07:16 +0000305 if (first_run)
306 p->verif_buff = b;
307 else
308 buffer_free (b);
William M. Brack9f797ab2004-07-28 07:40:12 +0000309 if (reader)
William M. Brack42331a92004-07-29 07:07:16 +0000310 xmlFreeTextReader (reader);
William M. Brack9f797ab2004-07-28 07:40:12 +0000311 return status;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000312}
313
314int main(int argc, char **argv) {
315 int i;
316 int files = 0;
317
318 if (argc <= 1) {
319 usage(argv[0]);
320 return(1);
321 }
322 LIBXML_TEST_VERSION;
323
324 xmlMemSetup (test_free,
325 test_malloc,
326 test_realloc,
327 test_strdup);
William M. Brack42331a92004-07-29 07:07:16 +0000328
329 xmlInitParser();
330
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000331 for (i = 1; i < argc ; i++) {
William M. Brack42331a92004-07-29 07:07:16 +0000332 if ((!strcmp(argv[i], "-count")) || (!strcmp(argv[i], "--count")))
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000333 count++;
334 else if ((!strcmp(argv[i], "-valid")) || (!strcmp(argv[i], "--valid")))
335 valid++;
336 else if ((!strcmp(argv[i], "-noent")) ||
337 (!strcmp(argv[i], "--noent")))
338 noent++;
William M. Brack42331a92004-07-29 07:07:16 +0000339 else if ((!strcmp(argv[i], "-show")) ||
340 (!strcmp(argv[i], "--show")))
341 showErrs++;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000342 }
343 if (noent != 0)
344 xmlSubstituteEntitiesDefault(1);
345 for (i = 1; i < argc ; i++) {
346 if (argv[i][0] != '-') {
William M. Brack9f797ab2004-07-28 07:40:12 +0000347 struct file_params p;
348 p.filename = argv[i];
William M. Brack42331a92004-07-29 07:07:16 +0000349 p.verif_buff = NULL;
William M. Brack9f797ab2004-07-28 07:40:12 +0000350
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000351 if (!test_oom_handling (check_load_file_memory_func,
William M. Brack9f797ab2004-07-28 07:40:12 +0000352 &p)) {
William M. Brack42331a92004-07-29 07:07:16 +0000353 fprintf (stdout, "Failed!\n");
354 return 1;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000355 }
356
William M. Brack42331a92004-07-29 07:07:16 +0000357 buffer_free (p.verif_buff);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000358 xmlCleanupParser();
359
360 if (test_get_malloc_blocks_outstanding () > 0) {
William M. Brack42331a92004-07-29 07:07:16 +0000361 fprintf (stdout, "%d blocks leaked\n",
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000362 test_get_malloc_blocks_outstanding ());
363 xmlMemoryDump();
William M. Brack42331a92004-07-29 07:07:16 +0000364 return 1;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000365 }
366
367 files ++;
368 }
369 }
370 xmlMemoryDump();
371
William M. Brack42331a92004-07-29 07:07:16 +0000372 return 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000373}