blob: 9ff13f2f9ba10d149f40604c128be5495897bf51 [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
William M. Bracka3215c72004-07-31 16:24:01 +000040int error = FALSE;
41int errcount = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +000042int noent = 0;
43int count = 0;
44int valid = 0;
William M. Brack42331a92004-07-29 07:07:16 +000045int 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
Daniel Veillardf8e3db02012-09-11 13:26:36 +080072/* not using xmlBuff here because I don't want those
William M. Brack42331a92004-07-29 07:07:16 +000073 * 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;
William M. Bracka3215c72004-07-31 16:24:01 +0000134 unsigned int ix;
William M. Brack42331a92004-07-29 07:07:16 +0000135 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
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000160
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");
William M. Brack42331a92004-07-29 07:07:16 +0000166 printf("\t --show: display the error messages encountered\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000167 exit(1);
168}
William M. Brack9f797ab2004-07-28 07:40:12 +0000169static unsigned int elem, attrs, chars;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000170
William M. Brack42331a92004-07-29 07:07:16 +0000171static int processNode (xmlTextReaderPtr reader, void *data)
172{
173 struct buffer *buff = data;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000174 int type;
175
176 type = xmlTextReaderNodeType(reader);
177 if (count) {
178 if (type == 1) {
179 elem++;
180 attrs += xmlTextReaderAttributeCount(reader);
William M. Brack9f797ab2004-07-28 07:40:12 +0000181 } 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;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000188 }
189 }
190
William M. Brack42331a92004-07-29 07:07:16 +0000191 if (buff != NULL) {
192 int ret;
193 const char *s;
194
195 buffer_add_string (buff, elementNames[type]);
196
197 if (type == 1) {
William M. Bracka3215c72004-07-31 16:24:01 +0000198 s = (const char *)xmlTextReaderConstName (reader);
William M. Brack42331a92004-07-29 07:07:16 +0000199 if (s == NULL) return FALSE;
200 buffer_add_string (buff, s);
201 while ((ret = xmlTextReaderMoveToNextAttribute (reader)) == 1) {
William M. Bracka3215c72004-07-31 16:24:01 +0000202 s = (const char *)xmlTextReaderConstName (reader);
William M. Brack42331a92004-07-29 07:07:16 +0000203 if (s == NULL) return FALSE;
204 buffer_add_string (buff, s);
205 buffer_add_char (buff, '=');
William M. Bracka3215c72004-07-31 16:24:01 +0000206 s = (const char *)xmlTextReaderConstValue (reader);
William M. Brack42331a92004-07-29 07:07:16 +0000207 if (s == NULL) return FALSE;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800208 buffer_add_string (buff, s);
William M. Brack42331a92004-07-29 07:07:16 +0000209 }
210 if (ret == -1) return FALSE;
211 }
212 else if (type == 3) {
William M. Bracka3215c72004-07-31 16:24:01 +0000213 s = (const char *)xmlTextReaderConstValue (reader);
William M. Brack42331a92004-07-29 07:07:16 +0000214 if (s == NULL) return FALSE;
215 buffer_add_string (buff, s);
216 }
217 }
218
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000219 return TRUE;
220}
221
William M. Brack9f797ab2004-07-28 07:40:12 +0000222
223struct file_params {
William M. Brack42331a92004-07-29 07:07:16 +0000224 const char *filename;
225 struct buffer *verif_buff;
William M. Brack9f797ab2004-07-28 07:40:12 +0000226};
227
William M. Brack42331a92004-07-29 07:07:16 +0000228static void
William M. Bracka3215c72004-07-31 16:24:01 +0000229error_func (void *data ATTRIBUTE_UNUSED, xmlErrorPtr err)
William M. Brack42331a92004-07-29 07:07:16 +0000230{
William M. Bracka3215c72004-07-31 16:24:01 +0000231
232 errcount++;
William M. Brack42331a92004-07-29 07:07:16 +0000233 if (err->level == XML_ERR_ERROR ||
234 err->level == XML_ERR_FATAL)
William M. Bracka3215c72004-07-31 16:24:01 +0000235 error = TRUE;
William M. Brack42331a92004-07-29 07:07:16 +0000236 if (showErrs) {
William M. Bracka3215c72004-07-31 16:24:01 +0000237 printf("%3d line %d: %s\n", error, err->line, err->message);
William M. Brack42331a92004-07-29 07:07:16 +0000238 }
239}
240
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000241static int
242check_load_file_memory_func (void *data)
243{
William M. Brack9f797ab2004-07-28 07:40:12 +0000244 struct file_params *p = data;
William M. Brack42331a92004-07-29 07:07:16 +0000245 struct buffer *b;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 xmlTextReaderPtr reader;
William M. Bracka3215c72004-07-31 16:24:01 +0000247 int ret, status, first_run;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000248
249 if (count) {
William M. Brack42331a92004-07-29 07:07:16 +0000250 elem = 0;
251 attrs = 0;
252 chars = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000253 }
254
William M. Brack42331a92004-07-29 07:07:16 +0000255 first_run = p->verif_buff == NULL;
William M. Brack9f797ab2004-07-28 07:40:12 +0000256 status = TRUE;
William M. Brack42331a92004-07-29 07:07:16 +0000257 error = FALSE;
258 if (first_run)
259 b = buffer_create (0);
260 else
261 b = buffer_create (buffer_get_length (p->verif_buff));
William M. Brack9f797ab2004-07-28 07:40:12 +0000262
William M. Brack42331a92004-07-29 07:07:16 +0000263 reader = xmlNewTextReaderFilename (p->filename);
264 if (reader == NULL)
265 goto out;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000266
William M. Bracka3215c72004-07-31 16:24:01 +0000267 xmlTextReaderSetStructuredErrorHandler (reader, error_func, NULL);
268 xmlSetStructuredErrorFunc(NULL, error_func);
William M. Brack42331a92004-07-29 07:07:16 +0000269
270 if (valid) {
271 if (xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1) == -1)
272 goto out;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000273 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800274
William M. Brack42331a92004-07-29 07:07:16 +0000275 /*
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) {
William M. Bracka3215c72004-07-31 16:24:01 +0000286 fprintf (stdout, "error handler was called but parse completed successfully (last error #%d)\n", errcount);
William M. Brack42331a92004-07-29 07:07:16 +0000287 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 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800300
William M. Brack42331a92004-07-29 07:07:16 +0000301 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
William M. Brack9f797ab2004-07-28 07:40:12 +0000308 out:
William M. Brack42331a92004-07-29 07:07:16 +0000309 if (first_run)
310 p->verif_buff = b;
311 else
312 buffer_free (b);
William M. Brack9f797ab2004-07-28 07:40:12 +0000313 if (reader)
William M. Brack42331a92004-07-29 07:07:16 +0000314 xmlFreeTextReader (reader);
William M. Brack9f797ab2004-07-28 07:40:12 +0000315 return status;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000316}
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 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800326 LIBXML_TEST_VERSION;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000327
328 xmlMemSetup (test_free,
329 test_malloc,
330 test_realloc,
331 test_strdup);
William M. Brack42331a92004-07-29 07:07:16 +0000332
333 xmlInitParser();
334
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000335 for (i = 1; i < argc ; i++) {
William M. Brack42331a92004-07-29 07:07:16 +0000336 if ((!strcmp(argv[i], "-count")) || (!strcmp(argv[i], "--count")))
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000337 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++;
William M. Brack42331a92004-07-29 07:07:16 +0000343 else if ((!strcmp(argv[i], "-show")) ||
344 (!strcmp(argv[i], "--show")))
345 showErrs++;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000346 }
347 if (noent != 0)
348 xmlSubstituteEntitiesDefault(1);
349 for (i = 1; i < argc ; i++) {
350 if (argv[i][0] != '-') {
William M. Brack9f797ab2004-07-28 07:40:12 +0000351 struct file_params p;
352 p.filename = argv[i];
William M. Brack42331a92004-07-29 07:07:16 +0000353 p.verif_buff = NULL;
William M. Brack9f797ab2004-07-28 07:40:12 +0000354
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000355 if (!test_oom_handling (check_load_file_memory_func,
William M. Brack9f797ab2004-07-28 07:40:12 +0000356 &p)) {
William M. Brack42331a92004-07-29 07:07:16 +0000357 fprintf (stdout, "Failed!\n");
358 return 1;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000359 }
360
William M. Brack42331a92004-07-29 07:07:16 +0000361 buffer_free (p.verif_buff);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000362 xmlCleanupParser();
363
364 if (test_get_malloc_blocks_outstanding () > 0) {
William M. Brack42331a92004-07-29 07:07:16 +0000365 fprintf (stdout, "%d blocks leaked\n",
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000366 test_get_malloc_blocks_outstanding ());
367 xmlMemoryDump();
William M. Brack42331a92004-07-29 07:07:16 +0000368 return 1;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000369 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800370
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000371 files ++;
372 }
373 }
374 xmlMemoryDump();
375
William M. Brack42331a92004-07-29 07:07:16 +0000376 return 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000377}