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
buffer_create(size_t init_len)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
buffer_free(struct buffer * b)98 static void buffer_free (struct buffer *b)
99 {
100 free (b->str);
101 free (b);
102 }
103
buffer_get_length(struct buffer * b)104 static size_t buffer_get_length (struct buffer *b)
105 {
106 return b->len;
107 }
108
buffer_expand(struct buffer * b,size_t min)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
buffer_add_char(struct buffer * b,char c)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
buffer_add_string(struct buffer * b,const char * s)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
buffer_equal(struct buffer * b1,struct buffer * b2)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
buffer_dump(struct buffer * b,const char * fname)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
usage(const char * progname)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
processNode(xmlTextReaderPtr reader,void * data)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
error_func(void * data ATTRIBUTE_UNUSED,xmlErrorPtr err)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
check_load_file_memory_func(void * data)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
main(int argc,char ** argv)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