VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/testlimits.c@ 106165

最後變更 在這個檔案從106165是 105420,由 vboxsync 提交於 4 月 前

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

  • 屬性 svn:eol-style 設為 native
檔案大小: 33.5 KB
 
1/*
2 * testlimits.c: C program to run libxml2 regression tests checking various
3 * limits in document size. Will consume a lot of RAM and CPU cycles
4 *
5 * To compile on Unixes:
6 * cc -o testlimits `xml2-config --cflags` testlimits.c `xml2-config --libs` -lpthread
7 *
8 * See Copyright for the status of this software.
9 *
10 * [email protected]
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <time.h>
18
19#include <libxml/parser.h>
20#include <libxml/parserInternals.h>
21#include <libxml/tree.h>
22#include <libxml/uri.h>
23#ifdef LIBXML_READER_ENABLED
24#include <libxml/xmlreader.h>
25#endif
26
27static int verbose = 0;
28static int tests_quiet = 0;
29
30/************************************************************************
31 * *
32 * time handling *
33 * *
34 ************************************************************************/
35
36/* maximum time for one parsing before declaring a timeout */
37#define MAX_TIME 2 /* seconds */
38
39static clock_t t0;
40int timeout = 0;
41
42static void reset_timout(void) {
43 timeout = 0;
44 t0 = clock();
45}
46
47static int check_time(void) {
48 clock_t tnow = clock();
49 if (((tnow - t0) / CLOCKS_PER_SEC) > MAX_TIME) {
50 timeout = 1;
51 return(0);
52 }
53 return(1);
54}
55
56/************************************************************************
57 * *
58 * Huge document generator *
59 * *
60 ************************************************************************/
61
62#include <libxml/xmlIO.h>
63
64/*
65 * Huge documents are built using fixed start and end chunks
66 * and filling between the two an unconventional amount of char data
67 */
68typedef struct hugeTest hugeTest;
69typedef hugeTest *hugeTestPtr;
70struct hugeTest {
71 const char *description;
72 const char *name;
73 const char *start;
74 const char *end;
75};
76
77static struct hugeTest hugeTests[] = {
78 { "Huge text node", "huge:textNode", "<foo>", "</foo>" },
79 { "Huge attribute node", "huge:attrNode", "<foo bar='", "'/>" },
80 { "Huge comment node", "huge:commentNode", "<foo><!--", "--></foo>" },
81 { "Huge PI node", "huge:piNode", "<foo><?bar ", "?></foo>" },
82};
83
84static const char *current;
85static int rlen;
86static unsigned int currentTest = 0;
87static int instate = 0;
88
89/**
90 * hugeMatch:
91 * @URI: an URI to test
92 *
93 * Check for an huge: query
94 *
95 * Returns 1 if yes and 0 if another Input module should be used
96 */
97static int
98hugeMatch(const char * URI) {
99 if ((URI != NULL) && (!strncmp(URI, "huge:", 5)))
100 return(1);
101 return(0);
102}
103
104/**
105 * hugeOpen:
106 * @URI: an URI to test
107 *
108 * Return a pointer to the huge: query handler, in this example simply
109 * the current pointer...
110 *
111 * Returns an Input context or NULL in case or error
112 */
113static void *
114hugeOpen(const char * URI) {
115 if ((URI == NULL) || (strncmp(URI, "huge:", 5)))
116 return(NULL);
117
118 for (currentTest = 0;currentTest < sizeof(hugeTests)/sizeof(hugeTests[0]);
119 currentTest++)
120 if (!strcmp(hugeTests[currentTest].name, URI))
121 goto found;
122
123 return(NULL);
124
125found:
126 rlen = strlen(hugeTests[currentTest].start);
127 current = hugeTests[currentTest].start;
128 instate = 0;
129 return((void *) current);
130}
131
132/**
133 * hugeClose:
134 * @context: the read context
135 *
136 * Close the huge: query handler
137 *
138 * Returns 0 or -1 in case of error
139 */
140static int
141hugeClose(void * context) {
142 if (context == NULL) return(-1);
143 fprintf(stderr, "\n");
144 return(0);
145}
146
147#define CHUNK 4096
148
149char filling[CHUNK + 1];
150
151static void fillFilling(void) {
152 int i;
153
154 for (i = 0;i < CHUNK;i++) {
155 filling[i] = 'a';
156 }
157 filling[CHUNK] = 0;
158}
159
160size_t maxlen = 64 * 1024 * 1024;
161size_t curlen = 0;
162size_t dotlen;
163
164/**
165 * hugeRead:
166 * @context: the read context
167 * @buffer: where to store data
168 * @len: number of bytes to read
169 *
170 * Implement an huge: query read.
171 *
172 * Returns the number of bytes read or -1 in case of error
173 */
174static int
175hugeRead(void *context, char *buffer, int len)
176{
177 if ((context == NULL) || (buffer == NULL) || (len < 0))
178 return (-1);
179
180 if (instate == 0) {
181 if (len >= rlen) {
182 len = rlen;
183 rlen = 0;
184 memcpy(buffer, current, len);
185 instate = 1;
186 curlen = 0;
187 dotlen = maxlen / 10;
188 } else {
189 memcpy(buffer, current, len);
190 rlen -= len;
191 current += len;
192 }
193 } else if (instate == 2) {
194 if (len >= rlen) {
195 len = rlen;
196 rlen = 0;
197 memcpy(buffer, current, len);
198 instate = 3;
199 curlen = 0;
200 } else {
201 memcpy(buffer, current, len);
202 rlen -= len;
203 current += len;
204 }
205 } else if (instate == 1) {
206 if (len > CHUNK) len = CHUNK;
207 memcpy(buffer, &filling[0], len);
208 curlen += len;
209 if (curlen >= maxlen) {
210 rlen = strlen(hugeTests[currentTest].end);
211 current = hugeTests[currentTest].end;
212 instate = 2;
213 } else {
214 if (curlen > dotlen) {
215 fprintf(stderr, ".");
216 dotlen += maxlen / 10;
217 }
218 }
219 } else
220 len = 0;
221 return (len);
222}
223
224/************************************************************************
225 * *
226 * Crazy document generator *
227 * *
228 ************************************************************************/
229
230unsigned int crazy_indx = 0;
231
232const char *crazy = "<?xml version='1.0' encoding='UTF-8'?>\
233<?tst ?>\
234<!-- tst -->\
235<!DOCTYPE foo [\
236<?tst ?>\
237<!-- tst -->\
238<!ELEMENT foo (#PCDATA)>\
239<!ELEMENT p (#PCDATA|emph)* >\
240]>\
241<?tst ?>\
242<!-- tst -->\
243<foo bar='foo'>\
244<?tst ?>\
245<!-- tst -->\
246foo\
247<![CDATA[ ]]>\
248</foo>\
249<?tst ?>\
250<!-- tst -->";
251
252/**
253 * crazyMatch:
254 * @URI: an URI to test
255 *
256 * Check for a crazy: query
257 *
258 * Returns 1 if yes and 0 if another Input module should be used
259 */
260static int
261crazyMatch(const char * URI) {
262 if ((URI != NULL) && (!strncmp(URI, "crazy:", 6)))
263 return(1);
264 return(0);
265}
266
267/**
268 * crazyOpen:
269 * @URI: an URI to test
270 *
271 * Return a pointer to the crazy: query handler, in this example simply
272 * the current pointer...
273 *
274 * Returns an Input context or NULL in case or error
275 */
276static void *
277crazyOpen(const char * URI) {
278 if ((URI == NULL) || (strncmp(URI, "crazy:", 6)))
279 return(NULL);
280
281 if (crazy_indx > strlen(crazy))
282 return(NULL);
283 reset_timout();
284 rlen = crazy_indx;
285 current = &crazy[0];
286 instate = 0;
287 return((void *) current);
288}
289
290/**
291 * crazyClose:
292 * @context: the read context
293 *
294 * Close the crazy: query handler
295 *
296 * Returns 0 or -1 in case of error
297 */
298static int
299crazyClose(void * context) {
300 if (context == NULL) return(-1);
301 return(0);
302}
303
304
305/**
306 * crazyRead:
307 * @context: the read context
308 * @buffer: where to store data
309 * @len: number of bytes to read
310 *
311 * Implement an crazy: query read.
312 *
313 * Returns the number of bytes read or -1 in case of error
314 */
315static int
316crazyRead(void *context, char *buffer, int len)
317{
318 if ((context == NULL) || (buffer == NULL) || (len < 0))
319 return (-1);
320
321 if ((check_time() <= 0) && (instate == 1)) {
322 fprintf(stderr, "\ntimeout in crazy(%d)\n", crazy_indx);
323 rlen = strlen(crazy) - crazy_indx;
324 current = &crazy[crazy_indx];
325 instate = 2;
326 }
327 if (instate == 0) {
328 if (len >= rlen) {
329 len = rlen;
330 rlen = 0;
331 memcpy(buffer, current, len);
332 instate = 1;
333 curlen = 0;
334 } else {
335 memcpy(buffer, current, len);
336 rlen -= len;
337 current += len;
338 }
339 } else if (instate == 2) {
340 if (len >= rlen) {
341 len = rlen;
342 rlen = 0;
343 memcpy(buffer, current, len);
344 instate = 3;
345 curlen = 0;
346 } else {
347 memcpy(buffer, current, len);
348 rlen -= len;
349 current += len;
350 }
351 } else if (instate == 1) {
352 if (len > CHUNK) len = CHUNK;
353 memcpy(buffer, &filling[0], len);
354 curlen += len;
355 if (curlen >= maxlen) {
356 rlen = strlen(crazy) - crazy_indx;
357 current = &crazy[crazy_indx];
358 instate = 2;
359 }
360 } else
361 len = 0;
362 return (len);
363}
364/************************************************************************
365 * *
366 * Libxml2 specific routines *
367 * *
368 ************************************************************************/
369
370static int nb_tests = 0;
371static int nb_errors = 0;
372static int nb_leaks = 0;
373static int extraMemoryFromResolver = 0;
374
375/*
376 * We need to trap calls to the resolver to not account memory for the catalog
377 * which is shared to the current running test. We also don't want to have
378 * network downloads modifying tests.
379 */
380static xmlParserInputPtr
381testExternalEntityLoader(const char *URL, const char *ID,
382 xmlParserCtxtPtr ctxt) {
383 xmlParserInputPtr ret;
384 int memused = xmlMemUsed();
385
386 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
387 extraMemoryFromResolver += xmlMemUsed() - memused;
388
389 return(ret);
390}
391
392static void
393initializeLibxml2(void) {
394 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
395 xmlInitParser();
396 xmlSetExternalEntityLoader(testExternalEntityLoader);
397 /*
398 * register the new I/O handlers
399 */
400 if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
401 hugeRead, hugeClose) < 0) {
402 fprintf(stderr, "failed to register Huge handlers\n");
403 exit(1);
404 }
405 if (xmlRegisterInputCallbacks(crazyMatch, crazyOpen,
406 crazyRead, crazyClose) < 0) {
407 fprintf(stderr, "failed to register Crazy handlers\n");
408 exit(1);
409 }
410}
411
412/************************************************************************
413 * *
414 * SAX empty callbacks *
415 * *
416 ************************************************************************/
417
418unsigned long callbacks = 0;
419
420/**
421 * isStandaloneCallback:
422 * @ctxt: An XML parser context
423 *
424 * Is this document tagged standalone ?
425 *
426 * Returns 1 if true
427 */
428static int
429isStandaloneCallback(void *ctx ATTRIBUTE_UNUSED)
430{
431 callbacks++;
432 return (0);
433}
434
435/**
436 * hasInternalSubsetCallback:
437 * @ctxt: An XML parser context
438 *
439 * Does this document has an internal subset
440 *
441 * Returns 1 if true
442 */
443static int
444hasInternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
445{
446 callbacks++;
447 return (0);
448}
449
450/**
451 * hasExternalSubsetCallback:
452 * @ctxt: An XML parser context
453 *
454 * Does this document has an external subset
455 *
456 * Returns 1 if true
457 */
458static int
459hasExternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
460{
461 callbacks++;
462 return (0);
463}
464
465/**
466 * internalSubsetCallback:
467 * @ctxt: An XML parser context
468 *
469 * Does this document has an internal subset
470 */
471static void
472internalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
473 const xmlChar * name ATTRIBUTE_UNUSED,
474 const xmlChar * ExternalID ATTRIBUTE_UNUSED,
475 const xmlChar * SystemID ATTRIBUTE_UNUSED)
476{
477 callbacks++;
478 return;
479}
480
481/**
482 * externalSubsetCallback:
483 * @ctxt: An XML parser context
484 *
485 * Does this document has an external subset
486 */
487static void
488externalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
489 const xmlChar * name ATTRIBUTE_UNUSED,
490 const xmlChar * ExternalID ATTRIBUTE_UNUSED,
491 const xmlChar * SystemID ATTRIBUTE_UNUSED)
492{
493 callbacks++;
494 return;
495}
496
497/**
498 * resolveEntityCallback:
499 * @ctxt: An XML parser context
500 * @publicId: The public ID of the entity
501 * @systemId: The system ID of the entity
502 *
503 * Special entity resolver, better left to the parser, it has
504 * more context than the application layer.
505 * The default behaviour is to NOT resolve the entities, in that case
506 * the ENTITY_REF nodes are built in the structure (and the parameter
507 * values).
508 *
509 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
510 */
511static xmlParserInputPtr
512resolveEntityCallback(void *ctx ATTRIBUTE_UNUSED,
513 const xmlChar * publicId ATTRIBUTE_UNUSED,
514 const xmlChar * systemId ATTRIBUTE_UNUSED)
515{
516 callbacks++;
517 return (NULL);
518}
519
520/**
521 * getEntityCallback:
522 * @ctxt: An XML parser context
523 * @name: The entity name
524 *
525 * Get an entity by name
526 *
527 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
528 */
529static xmlEntityPtr
530getEntityCallback(void *ctx ATTRIBUTE_UNUSED,
531 const xmlChar * name ATTRIBUTE_UNUSED)
532{
533 callbacks++;
534 return (NULL);
535}
536
537/**
538 * getParameterEntityCallback:
539 * @ctxt: An XML parser context
540 * @name: The entity name
541 *
542 * Get a parameter entity by name
543 *
544 * Returns the xmlParserInputPtr
545 */
546static xmlEntityPtr
547getParameterEntityCallback(void *ctx ATTRIBUTE_UNUSED,
548 const xmlChar * name ATTRIBUTE_UNUSED)
549{
550 callbacks++;
551 return (NULL);
552}
553
554
555/**
556 * entityDeclCallback:
557 * @ctxt: An XML parser context
558 * @name: the entity name
559 * @type: the entity type
560 * @publicId: The public ID of the entity
561 * @systemId: The system ID of the entity
562 * @content: the entity value (without processing).
563 *
564 * An entity definition has been parsed
565 */
566static void
567entityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
568 const xmlChar * name ATTRIBUTE_UNUSED,
569 int type ATTRIBUTE_UNUSED,
570 const xmlChar * publicId ATTRIBUTE_UNUSED,
571 const xmlChar * systemId ATTRIBUTE_UNUSED,
572 xmlChar * content ATTRIBUTE_UNUSED)
573{
574 callbacks++;
575 return;
576}
577
578/**
579 * attributeDeclCallback:
580 * @ctxt: An XML parser context
581 * @name: the attribute name
582 * @type: the attribute type
583 *
584 * An attribute definition has been parsed
585 */
586static void
587attributeDeclCallback(void *ctx ATTRIBUTE_UNUSED,
588 const xmlChar * elem ATTRIBUTE_UNUSED,
589 const xmlChar * name ATTRIBUTE_UNUSED,
590 int type ATTRIBUTE_UNUSED, int def ATTRIBUTE_UNUSED,
591 const xmlChar * defaultValue ATTRIBUTE_UNUSED,
592 xmlEnumerationPtr tree ATTRIBUTE_UNUSED)
593{
594 callbacks++;
595 return;
596}
597
598/**
599 * elementDeclCallback:
600 * @ctxt: An XML parser context
601 * @name: the element name
602 * @type: the element type
603 * @content: the element value (without processing).
604 *
605 * An element definition has been parsed
606 */
607static void
608elementDeclCallback(void *ctx ATTRIBUTE_UNUSED,
609 const xmlChar * name ATTRIBUTE_UNUSED,
610 int type ATTRIBUTE_UNUSED,
611 xmlElementContentPtr content ATTRIBUTE_UNUSED)
612{
613 callbacks++;
614 return;
615}
616
617/**
618 * notationDeclCallback:
619 * @ctxt: An XML parser context
620 * @name: The name of the notation
621 * @publicId: The public ID of the entity
622 * @systemId: The system ID of the entity
623 *
624 * What to do when a notation declaration has been parsed.
625 */
626static void
627notationDeclCallback(void *ctx ATTRIBUTE_UNUSED,
628 const xmlChar * name ATTRIBUTE_UNUSED,
629 const xmlChar * publicId ATTRIBUTE_UNUSED,
630 const xmlChar * systemId ATTRIBUTE_UNUSED)
631{
632 callbacks++;
633 return;
634}
635
636/**
637 * unparsedEntityDeclCallback:
638 * @ctxt: An XML parser context
639 * @name: The name of the entity
640 * @publicId: The public ID of the entity
641 * @systemId: The system ID of the entity
642 * @notationName: the name of the notation
643 *
644 * What to do when an unparsed entity declaration is parsed
645 */
646static void
647unparsedEntityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
648 const xmlChar * name ATTRIBUTE_UNUSED,
649 const xmlChar * publicId ATTRIBUTE_UNUSED,
650 const xmlChar * systemId ATTRIBUTE_UNUSED,
651 const xmlChar * notationName ATTRIBUTE_UNUSED)
652{
653 callbacks++;
654 return;
655}
656
657/**
658 * setDocumentLocatorCallback:
659 * @ctxt: An XML parser context
660 * @loc: A SAX Locator
661 *
662 * Receive the document locator at startup, actually xmlDefaultSAXLocator
663 * Everything is available on the context, so this is useless in our case.
664 */
665static void
666setDocumentLocatorCallback(void *ctx ATTRIBUTE_UNUSED,
667 xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
668{
669 callbacks++;
670 return;
671}
672
673/**
674 * startDocumentCallback:
675 * @ctxt: An XML parser context
676 *
677 * called when the document start being processed.
678 */
679static void
680startDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
681{
682 callbacks++;
683 return;
684}
685
686/**
687 * endDocumentCallback:
688 * @ctxt: An XML parser context
689 *
690 * called when the document end has been detected.
691 */
692static void
693endDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
694{
695 callbacks++;
696 return;
697}
698
699#if 0
700/**
701 * startElementCallback:
702 * @ctxt: An XML parser context
703 * @name: The element name
704 *
705 * called when an opening tag has been processed.
706 */
707static void
708startElementCallback(void *ctx ATTRIBUTE_UNUSED,
709 const xmlChar * name ATTRIBUTE_UNUSED,
710 const xmlChar ** atts ATTRIBUTE_UNUSED)
711{
712 callbacks++;
713 return;
714}
715
716/**
717 * endElementCallback:
718 * @ctxt: An XML parser context
719 * @name: The element name
720 *
721 * called when the end of an element has been detected.
722 */
723static void
724endElementCallback(void *ctx ATTRIBUTE_UNUSED,
725 const xmlChar * name ATTRIBUTE_UNUSED)
726{
727 callbacks++;
728 return;
729}
730#endif
731
732/**
733 * charactersCallback:
734 * @ctxt: An XML parser context
735 * @ch: a xmlChar string
736 * @len: the number of xmlChar
737 *
738 * receiving some chars from the parser.
739 * Question: how much at a time ???
740 */
741static void
742charactersCallback(void *ctx ATTRIBUTE_UNUSED,
743 const xmlChar * ch ATTRIBUTE_UNUSED,
744 int len ATTRIBUTE_UNUSED)
745{
746 callbacks++;
747 return;
748}
749
750/**
751 * referenceCallback:
752 * @ctxt: An XML parser context
753 * @name: The entity name
754 *
755 * called when an entity reference is detected.
756 */
757static void
758referenceCallback(void *ctx ATTRIBUTE_UNUSED,
759 const xmlChar * name ATTRIBUTE_UNUSED)
760{
761 callbacks++;
762 return;
763}
764
765/**
766 * ignorableWhitespaceCallback:
767 * @ctxt: An XML parser context
768 * @ch: a xmlChar string
769 * @start: the first char in the string
770 * @len: the number of xmlChar
771 *
772 * receiving some ignorable whitespaces from the parser.
773 * Question: how much at a time ???
774 */
775static void
776ignorableWhitespaceCallback(void *ctx ATTRIBUTE_UNUSED,
777 const xmlChar * ch ATTRIBUTE_UNUSED,
778 int len ATTRIBUTE_UNUSED)
779{
780 callbacks++;
781 return;
782}
783
784/**
785 * processingInstructionCallback:
786 * @ctxt: An XML parser context
787 * @target: the target name
788 * @data: the PI data's
789 * @len: the number of xmlChar
790 *
791 * A processing instruction has been parsed.
792 */
793static void
794processingInstructionCallback(void *ctx ATTRIBUTE_UNUSED,
795 const xmlChar * target ATTRIBUTE_UNUSED,
796 const xmlChar * data ATTRIBUTE_UNUSED)
797{
798 callbacks++;
799 return;
800}
801
802/**
803 * cdataBlockCallback:
804 * @ctx: the user data (XML parser context)
805 * @value: The pcdata content
806 * @len: the block length
807 *
808 * called when a pcdata block has been parsed
809 */
810static void
811cdataBlockCallback(void *ctx ATTRIBUTE_UNUSED,
812 const xmlChar * value ATTRIBUTE_UNUSED,
813 int len ATTRIBUTE_UNUSED)
814{
815 callbacks++;
816 return;
817}
818
819/**
820 * commentCallback:
821 * @ctxt: An XML parser context
822 * @value: the comment content
823 *
824 * A comment has been parsed.
825 */
826static void
827commentCallback(void *ctx ATTRIBUTE_UNUSED,
828 const xmlChar * value ATTRIBUTE_UNUSED)
829{
830 callbacks++;
831 return;
832}
833
834/**
835 * warningCallback:
836 * @ctxt: An XML parser context
837 * @msg: the message to display/transmit
838 * @...: extra parameters for the message display
839 *
840 * Display and format a warning messages, gives file, line, position and
841 * extra parameters.
842 */
843static void
844warningCallback(void *ctx ATTRIBUTE_UNUSED,
845 const char *msg ATTRIBUTE_UNUSED, ...)
846{
847 callbacks++;
848 return;
849}
850
851/**
852 * errorCallback:
853 * @ctxt: An XML parser context
854 * @msg: the message to display/transmit
855 * @...: extra parameters for the message display
856 *
857 * Display and format a error messages, gives file, line, position and
858 * extra parameters.
859 */
860static void
861errorCallback(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
862 ...)
863{
864 callbacks++;
865 return;
866}
867
868/**
869 * fatalErrorCallback:
870 * @ctxt: An XML parser context
871 * @msg: the message to display/transmit
872 * @...: extra parameters for the message display
873 *
874 * Display and format a fatalError messages, gives file, line, position and
875 * extra parameters.
876 */
877static void
878fatalErrorCallback(void *ctx ATTRIBUTE_UNUSED,
879 const char *msg ATTRIBUTE_UNUSED, ...)
880{
881 return;
882}
883
884
885/*
886 * SAX2 specific callbacks
887 */
888
889/**
890 * startElementNsCallback:
891 * @ctxt: An XML parser context
892 * @name: The element name
893 *
894 * called when an opening tag has been processed.
895 */
896static void
897startElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
898 const xmlChar * localname ATTRIBUTE_UNUSED,
899 const xmlChar * prefix ATTRIBUTE_UNUSED,
900 const xmlChar * URI ATTRIBUTE_UNUSED,
901 int nb_namespaces ATTRIBUTE_UNUSED,
902 const xmlChar ** namespaces ATTRIBUTE_UNUSED,
903 int nb_attributes ATTRIBUTE_UNUSED,
904 int nb_defaulted ATTRIBUTE_UNUSED,
905 const xmlChar ** attributes ATTRIBUTE_UNUSED)
906{
907 callbacks++;
908 return;
909}
910
911/**
912 * endElementCallback:
913 * @ctxt: An XML parser context
914 * @name: The element name
915 *
916 * called when the end of an element has been detected.
917 */
918static void
919endElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
920 const xmlChar * localname ATTRIBUTE_UNUSED,
921 const xmlChar * prefix ATTRIBUTE_UNUSED,
922 const xmlChar * URI ATTRIBUTE_UNUSED)
923{
924 callbacks++;
925 return;
926}
927
928static xmlSAXHandler callbackSAX2HandlerStruct = {
929 internalSubsetCallback,
930 isStandaloneCallback,
931 hasInternalSubsetCallback,
932 hasExternalSubsetCallback,
933 resolveEntityCallback,
934 getEntityCallback,
935 entityDeclCallback,
936 notationDeclCallback,
937 attributeDeclCallback,
938 elementDeclCallback,
939 unparsedEntityDeclCallback,
940 setDocumentLocatorCallback,
941 startDocumentCallback,
942 endDocumentCallback,
943 NULL,
944 NULL,
945 referenceCallback,
946 charactersCallback,
947 ignorableWhitespaceCallback,
948 processingInstructionCallback,
949 commentCallback,
950 warningCallback,
951 errorCallback,
952 fatalErrorCallback,
953 getParameterEntityCallback,
954 cdataBlockCallback,
955 externalSubsetCallback,
956 XML_SAX2_MAGIC,
957 NULL,
958 startElementNsCallback,
959 endElementNsCallback,
960 NULL
961};
962
963static xmlSAXHandlerPtr callbackSAX2Handler = &callbackSAX2HandlerStruct;
964
965/************************************************************************
966 * *
967 * The tests front-ends *
968 * *
969 ************************************************************************/
970
971/**
972 * readerTest:
973 * @filename: the file to parse
974 * @max_size: size of the limit to test
975 * @options: parsing options
976 * @fail: should a failure be reported
977 *
978 * Parse a memory generated file using SAX
979 *
980 * Returns 0 in case of success, an error code otherwise
981 */
982static int
983saxTest(const char *filename, size_t limit, int options, int fail) {
984 int res = 0;
985 xmlParserCtxtPtr ctxt;
986 xmlDocPtr doc;
987
988 nb_tests++;
989
990 maxlen = limit;
991 ctxt = xmlNewSAXParserCtxt(callbackSAX2Handler, NULL);
992 if (ctxt == NULL) {
993 fprintf(stderr, "Failed to create parser context\n");
994 return(1);
995 }
996 doc = xmlCtxtReadFile(ctxt, filename, NULL, options | XML_PARSE_NOERROR);
997
998 if (doc != NULL) {
999 fprintf(stderr, "SAX parsing generated a document !\n");
1000 xmlFreeDoc(doc);
1001 res = 0;
1002 } else if (ctxt->wellFormed == 0) {
1003 if (fail)
1004 res = 0;
1005 else {
1006 fprintf(stderr, "Failed to parse '%s' %lu\n", filename,
1007 (unsigned long) limit);
1008 res = 1;
1009 }
1010 } else {
1011 if (fail) {
1012 fprintf(stderr, "Failed to get failure for '%s' %lu\n",
1013 filename, (unsigned long) limit);
1014 res = 1;
1015 } else
1016 res = 0;
1017 }
1018 xmlFreeParserCtxt(ctxt);
1019
1020 return(res);
1021}
1022#ifdef LIBXML_READER_ENABLED
1023/**
1024 * readerTest:
1025 * @filename: the file to parse
1026 * @max_size: size of the limit to test
1027 * @options: parsing options
1028 * @fail: should a failure be reported
1029 *
1030 * Parse a memory generated file using the xmlReader
1031 *
1032 * Returns 0 in case of success, an error code otherwise
1033 */
1034static int
1035readerTest(const char *filename, size_t limit, int options, int fail) {
1036 xmlTextReaderPtr reader;
1037 int res = 0;
1038 int ret;
1039
1040 nb_tests++;
1041
1042 maxlen = limit;
1043 reader = xmlReaderForFile(filename , NULL, options | XML_PARSE_NOERROR);
1044 if (reader == NULL) {
1045 fprintf(stderr, "Failed to open '%s' test\n", filename);
1046 return(1);
1047 }
1048 ret = xmlTextReaderRead(reader);
1049 while (ret == 1) {
1050 ret = xmlTextReaderRead(reader);
1051 }
1052 if (ret != 0) {
1053 if (fail)
1054 res = 0;
1055 else {
1056 if (strncmp(filename, "crazy:", 6) == 0)
1057 fprintf(stderr, "Failed to parse '%s' %u\n",
1058 filename, crazy_indx);
1059 else
1060 fprintf(stderr, "Failed to parse '%s' %lu\n",
1061 filename, (unsigned long) limit);
1062 res = 1;
1063 }
1064 } else {
1065 if (fail) {
1066 if (strncmp(filename, "crazy:", 6) == 0)
1067 fprintf(stderr, "Failed to get failure for '%s' %u\n",
1068 filename, crazy_indx);
1069 else
1070 fprintf(stderr, "Failed to get failure for '%s' %lu\n",
1071 filename, (unsigned long) limit);
1072 res = 1;
1073 } else
1074 res = 0;
1075 }
1076 if (timeout)
1077 res = 1;
1078 xmlFreeTextReader(reader);
1079
1080 return(res);
1081}
1082#endif
1083
1084/************************************************************************
1085 * *
1086 * Tests descriptions *
1087 * *
1088 ************************************************************************/
1089
1090typedef int (*functest) (const char *filename, size_t limit, int options,
1091 int fail);
1092
1093typedef struct limitDesc limitDesc;
1094typedef limitDesc *limitDescPtr;
1095struct limitDesc {
1096 const char *name; /* the huge generator name */
1097 size_t limit; /* the limit to test */
1098 int options; /* extra parser options */
1099 int fail; /* whether the test should fail */
1100};
1101
1102static limitDesc limitDescriptions[] = {
1103 /* max length of a text node in content */
1104 {"huge:textNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1105 {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1106 {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1107 /* max length of a text node in content */
1108 {"huge:attrNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1109 {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1110 {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1111 /* max length of a comment node */
1112 {"huge:commentNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1113 {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1114 {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1115 /* max length of a PI node */
1116 {"huge:piNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1117 {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1118 {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1119};
1120
1121typedef struct testDesc testDesc;
1122typedef testDesc *testDescPtr;
1123struct testDesc {
1124 const char *desc; /* description of the test */
1125 functest func; /* function implementing the test */
1126};
1127
1128static
1129testDesc testDescriptions[] = {
1130 { "Parsing of huge files with the sax parser", saxTest},
1131/* { "Parsing of huge files with the tree parser", treeTest}, */
1132#ifdef LIBXML_READER_ENABLED
1133 { "Parsing of huge files with the reader", readerTest},
1134#endif
1135 {NULL, NULL}
1136};
1137
1138typedef struct testException testException;
1139typedef testException *testExceptionPtr;
1140struct testException {
1141 unsigned int test; /* the parser test number */
1142 unsigned int limit; /* the limit test number */
1143 int fail; /* new fail value or -1*/
1144 size_t size; /* new limit value or 0 */
1145};
1146
1147static
1148testException testExceptions[] = {
1149 /* the SAX parser doesn't hit a limit of XML_MAX_TEXT_LENGTH text nodes */
1150 { 0, 1, 0, 0},
1151};
1152
1153static int
1154launchTests(testDescPtr tst, unsigned int test) {
1155 int res = 0, err = 0;
1156 unsigned int i, j;
1157 size_t limit;
1158 int fail;
1159
1160 if (tst == NULL) return(-1);
1161
1162 for (i = 0;i < sizeof(limitDescriptions)/sizeof(limitDescriptions[0]);i++) {
1163 limit = limitDescriptions[i].limit;
1164 fail = limitDescriptions[i].fail;
1165 /*
1166 * Handle exceptions if any
1167 */
1168 for (j = 0;j < sizeof(testExceptions)/sizeof(testExceptions[0]);j++) {
1169 if ((testExceptions[j].test == test) &&
1170 (testExceptions[j].limit == i)) {
1171 if (testExceptions[j].fail != -1)
1172 fail = testExceptions[j].fail;
1173 if (testExceptions[j].size != 0)
1174 limit = testExceptions[j].size;
1175 break;
1176 }
1177 }
1178 res = tst->func(limitDescriptions[i].name, limit,
1179 limitDescriptions[i].options, fail);
1180 if (res != 0) {
1181 nb_errors++;
1182 err++;
1183 }
1184 }
1185 return(err);
1186}
1187
1188
1189static int
1190runtest(unsigned int i) {
1191 int ret = 0, res;
1192 int old_errors, old_tests, old_leaks;
1193
1194 old_errors = nb_errors;
1195 old_tests = nb_tests;
1196 old_leaks = nb_leaks;
1197 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
1198 printf("## %s\n", testDescriptions[i].desc);
1199 res = launchTests(&testDescriptions[i], i);
1200 if (res != 0)
1201 ret++;
1202 if (verbose) {
1203 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1204 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1205 else
1206 printf("Ran %d tests, %d errors, %d leaks\n",
1207 nb_tests - old_tests,
1208 nb_errors - old_errors,
1209 nb_leaks - old_leaks);
1210 }
1211 return(ret);
1212}
1213
1214static int
1215launchCrazySAX(unsigned int test, int fail) {
1216 int res = 0, err = 0;
1217
1218 crazy_indx = test;
1219
1220 res = saxTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
1221 if (res != 0) {
1222 nb_errors++;
1223 err++;
1224 }
1225 if (tests_quiet == 0)
1226 fprintf(stderr, "%c", crazy[test]);
1227
1228 return(err);
1229}
1230
1231#ifdef LIBXML_READER_ENABLED
1232static int
1233launchCrazy(unsigned int test, int fail) {
1234 int res = 0, err = 0;
1235
1236 crazy_indx = test;
1237
1238 res = readerTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
1239 if (res != 0) {
1240 nb_errors++;
1241 err++;
1242 }
1243 if (tests_quiet == 0)
1244 fprintf(stderr, "%c", crazy[test]);
1245
1246 return(err);
1247}
1248#endif
1249
1250static int get_crazy_fail(int test) {
1251 /*
1252 * adding 1000000 of character 'a' leads to parser failure mostly
1253 * everywhere except in those special spots. Need to be updated
1254 * each time crazy is updated
1255 */
1256 int fail = 1;
1257 if ((test == 44) || /* PI in Misc */
1258 ((test >= 50) && (test <= 55)) || /* Comment in Misc */
1259 (test == 79) || /* PI in DTD */
1260 ((test >= 85) && (test <= 90)) || /* Comment in DTD */
1261 (test == 154) || /* PI in Misc */
1262 ((test >= 160) && (test <= 165)) || /* Comment in Misc */
1263 ((test >= 178) && (test <= 181)) || /* attribute value */
1264 (test == 183) || /* Text */
1265 (test == 189) || /* PI in Content */
1266 (test == 191) || /* Text */
1267 ((test >= 195) && (test <= 200)) || /* Comment in Content */
1268 ((test >= 203) && (test <= 206)) || /* Text */
1269 (test == 215) || (test == 216) || /* in CDATA */
1270 (test == 219) || /* Text */
1271 (test == 231) || /* PI in Misc */
1272 ((test >= 237) && (test <= 242))) /* Comment in Misc */
1273 fail = 0;
1274 return(fail);
1275}
1276
1277static int
1278runcrazy(void) {
1279 int ret = 0, res = 0;
1280 int old_errors, old_tests, old_leaks;
1281 unsigned int i;
1282
1283 old_errors = nb_errors;
1284 old_tests = nb_tests;
1285 old_leaks = nb_leaks;
1286
1287#ifdef LIBXML_READER_ENABLED
1288 if (tests_quiet == 0) {
1289 printf("## Crazy tests on reader\n");
1290 }
1291 for (i = 0;i < strlen(crazy);i++) {
1292 res += launchCrazy(i, get_crazy_fail(i));
1293 if (res != 0)
1294 ret++;
1295 }
1296#endif
1297
1298 if (tests_quiet == 0) {
1299 printf("\n## Crazy tests on SAX\n");
1300 }
1301 for (i = 0;i < strlen(crazy);i++) {
1302 res += launchCrazySAX(i, get_crazy_fail(i));
1303 if (res != 0)
1304 ret++;
1305 }
1306 if (tests_quiet == 0)
1307 fprintf(stderr, "\n");
1308 if (verbose) {
1309 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1310 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1311 else
1312 printf("Ran %d tests, %d errors, %d leaks\n",
1313 nb_tests - old_tests,
1314 nb_errors - old_errors,
1315 nb_leaks - old_leaks);
1316 }
1317 return(ret);
1318}
1319
1320
1321int
1322main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1323 int i, a, ret = 0;
1324 int subset = 0;
1325
1326 fillFilling();
1327 initializeLibxml2();
1328
1329 for (a = 1; a < argc;a++) {
1330 if (!strcmp(argv[a], "-v"))
1331 verbose = 1;
1332 else if (!strcmp(argv[a], "-quiet"))
1333 tests_quiet = 1;
1334 else if (!strcmp(argv[a], "-crazy"))
1335 subset = 1;
1336 }
1337 if (subset == 0) {
1338 for (i = 0; testDescriptions[i].func != NULL; i++) {
1339 ret += runtest(i);
1340 }
1341 }
1342 ret += runcrazy();
1343 if ((nb_errors == 0) && (nb_leaks == 0)) {
1344 ret = 0;
1345 printf("Total %d tests, no errors\n",
1346 nb_tests);
1347 } else {
1348 ret = 1;
1349 printf("Total %d tests, %d errors, %d leaks\n",
1350 nb_tests, nb_errors, nb_leaks);
1351 }
1352 xmlCleanupParser();
1353
1354 return(ret);
1355}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette