xref: /freebsd/sys/contrib/zlib/test/infcover.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 /* infcover.c -- test zlib's inflate routines with full code coverage
2  * Copyright (C) 2011, 2016 Mark Adler
3  * For conditions of distribution and use, see copyright notice in zlib.h
4  */
5 
6 /* to use, do: ./configure --cover && make cover */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include "zlib.h"
13 
14 /* get definition of internal structure so we can mess with it (see pull()),
15    and so we can call inflate_trees() (see cover5()) */
16 #define ZLIB_INTERNAL
17 #include "inftrees.h"
18 #include "inflate.h"
19 
20 #define local static
21 
22 /* -- memory tracking routines -- */
23 
24 /*
25    These memory tracking routines are provided to zlib and track all of zlib's
26    allocations and deallocations, check for LIFO operations, keep a current
27    and high water mark of total bytes requested, optionally set a limit on the
28    total memory that can be allocated, and when done check for memory leaks.
29 
30    They are used as follows:
31 
32    z_stream strm;
33    mem_setup(&strm)         initializes the memory tracking and sets the
34                             zalloc, zfree, and opaque members of strm to use
35                             memory tracking for all zlib operations on strm
36    mem_limit(&strm, limit)  sets a limit on the total bytes requested -- a
37                             request that exceeds this limit will result in an
38                             allocation failure (returns NULL) -- setting the
39                             limit to zero means no limit, which is the default
40                             after mem_setup()
41    mem_used(&strm, "msg")   prints to stderr "msg" and the total bytes used
42    mem_high(&strm, "msg")   prints to stderr "msg" and the high water mark
43    mem_done(&strm, "msg")   ends memory tracking, releases all allocations
44                             for the tracking as well as leaked zlib blocks, if
45                             any.  If there was anything unusual, such as leaked
46                             blocks, non-FIFO frees, or frees of addresses not
47                             allocated, then "msg" and information about the
48                             problem is printed to stderr.  If everything is
49                             normal, nothing is printed. mem_done resets the
50                             strm members to Z_NULL to use the default memory
51                             allocation routines on the next zlib initialization
52                             using strm.
53  */
54 
55 /* these items are strung together in a linked list, one for each allocation */
56 struct mem_item {
57     void *ptr;                  /* pointer to allocated memory */
58     size_t size;                /* requested size of allocation */
59     struct mem_item *next;      /* pointer to next item in list, or NULL */
60 };
61 
62 /* this structure is at the root of the linked list, and tracks statistics */
63 struct mem_zone {
64     struct mem_item *first;     /* pointer to first item in list, or NULL */
65     size_t total, highwater;    /* total allocations, and largest total */
66     size_t limit;               /* memory allocation limit, or 0 if no limit */
67     int notlifo, rogue;         /* counts of non-LIFO frees and rogue frees */
68 };
69 
70 /* memory allocation routine to pass to zlib */
71 local void *mem_alloc(void *mem, unsigned count, unsigned size)
72 {
73     void *ptr;
74     struct mem_item *item;
75     struct mem_zone *zone = mem;
76     size_t len = count * (size_t)size;
77 
78     /* induced allocation failure */
79     if (zone == NULL || (zone->limit && zone->total + len > zone->limit))
80         return NULL;
81 
82     /* perform allocation using the standard library, fill memory with a
83        non-zero value to make sure that the code isn't depending on zeros */
84     ptr = malloc(len);
85     if (ptr == NULL)
86         return NULL;
87     memset(ptr, 0xa5, len);
88 
89     /* create a new item for the list */
90     item = malloc(sizeof(struct mem_item));
91     if (item == NULL) {
92         free(ptr);
93         return NULL;
94     }
95     item->ptr = ptr;
96     item->size = len;
97 
98     /* insert item at the beginning of the list */
99     item->next = zone->first;
100     zone->first = item;
101 
102     /* update the statistics */
103     zone->total += item->size;
104     if (zone->total > zone->highwater)
105         zone->highwater = zone->total;
106 
107     /* return the allocated memory */
108     return ptr;
109 }
110 
111 /* memory free routine to pass to zlib */
112 local void mem_free(void *mem, void *ptr)
113 {
114     struct mem_item *item, *next;
115     struct mem_zone *zone = mem;
116 
117     /* if no zone, just do a free */
118     if (zone == NULL) {
119         free(ptr);
120         return;
121     }
122 
123     /* point next to the item that matches ptr, or NULL if not found -- remove
124        the item from the linked list if found */
125     next = zone->first;
126     if (next) {
127         if (next->ptr == ptr)
128             zone->first = next->next;   /* first one is it, remove from list */
129         else {
130             do {                        /* search the linked list */
131                 item = next;
132                 next = item->next;
133             } while (next != NULL && next->ptr != ptr);
134             if (next) {                 /* if found, remove from linked list */
135                 item->next = next->next;
136                 zone->notlifo++;        /* not a LIFO free */
137             }
138 
139         }
140     }
141 
142     /* if found, update the statistics and free the item */
143     if (next) {
144         zone->total -= next->size;
145         free(next);
146     }
147 
148     /* if not found, update the rogue count */
149     else
150         zone->rogue++;
151 
152     /* in any case, do the requested free with the standard library function */
153     free(ptr);
154 }
155 
156 /* set up a controlled memory allocation space for monitoring, set the stream
157    parameters to the controlled routines, with opaque pointing to the space */
158 local void mem_setup(z_stream *strm)
159 {
160     struct mem_zone *zone;
161 
162     zone = malloc(sizeof(struct mem_zone));
163     assert(zone != NULL);
164     zone->first = NULL;
165     zone->total = 0;
166     zone->highwater = 0;
167     zone->limit = 0;
168     zone->notlifo = 0;
169     zone->rogue = 0;
170     strm->opaque = zone;
171     strm->zalloc = mem_alloc;
172     strm->zfree = mem_free;
173 }
174 
175 /* set a limit on the total memory allocation, or 0 to remove the limit */
176 local void mem_limit(z_stream *strm, size_t limit)
177 {
178     struct mem_zone *zone = strm->opaque;
179 
180     zone->limit = limit;
181 }
182 
183 /* show the current total requested allocations in bytes */
184 local void mem_used(z_stream *strm, char *prefix)
185 {
186     struct mem_zone *zone = strm->opaque;
187 
188     fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total);
189 }
190 
191 /* show the high water allocation in bytes */
192 local void mem_high(z_stream *strm, char *prefix)
193 {
194     struct mem_zone *zone = strm->opaque;
195 
196     fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater);
197 }
198 
199 /* release the memory allocation zone -- if there are any surprises, notify */
200 local void mem_done(z_stream *strm, char *prefix)
201 {
202     int count = 0;
203     struct mem_item *item, *next;
204     struct mem_zone *zone = strm->opaque;
205 
206     /* show high water mark */
207     mem_high(strm, prefix);
208 
209     /* free leftover allocations and item structures, if any */
210     item = zone->first;
211     while (item != NULL) {
212         free(item->ptr);
213         next = item->next;
214         free(item);
215         item = next;
216         count++;
217     }
218 
219     /* issue alerts about anything unexpected */
220     if (count || zone->total)
221         fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n",
222                 prefix, zone->total, count);
223     if (zone->notlifo)
224         fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo);
225     if (zone->rogue)
226         fprintf(stderr, "** %s: %d frees not recognized\n",
227                 prefix, zone->rogue);
228 
229     /* free the zone and delete from the stream */
230     free(zone);
231     strm->opaque = Z_NULL;
232     strm->zalloc = Z_NULL;
233     strm->zfree = Z_NULL;
234 }
235 
236 /* -- inflate test routines -- */
237 
238 /* Decode a hexadecimal string, set *len to length, in[] to the bytes.  This
239    decodes liberally, in that hex digits can be adjacent, in which case two in
240    a row writes a byte.  Or they can be delimited by any non-hex character,
241    where the delimiters are ignored except when a single hex digit is followed
242    by a delimiter, where that single digit writes a byte.  The returned data is
243    allocated and must eventually be freed.  NULL is returned if out of memory.
244    If the length is not needed, then len can be NULL. */
245 local unsigned char *h2b(const char *hex, unsigned *len)
246 {
247     unsigned char *in, *re;
248     unsigned next, val;
249 
250     in = malloc((strlen(hex) + 1) >> 1);
251     if (in == NULL)
252         return NULL;
253     next = 0;
254     val = 1;
255     do {
256         if (*hex >= '0' && *hex <= '9')
257             val = (val << 4) + *hex - '0';
258         else if (*hex >= 'A' && *hex <= 'F')
259             val = (val << 4) + *hex - 'A' + 10;
260         else if (*hex >= 'a' && *hex <= 'f')
261             val = (val << 4) + *hex - 'a' + 10;
262         else if (val != 1 && val < 32)  /* one digit followed by delimiter */
263             val += 240;                 /* make it look like two digits */
264         if (val > 255) {                /* have two digits */
265             in[next++] = val & 0xff;    /* save the decoded byte */
266             val = 1;                    /* start over */
267         }
268     } while (*hex++);       /* go through the loop with the terminating null */
269     if (len != NULL)
270         *len = next;
271     re = realloc(in, next);
272     return re == NULL ? in : re;
273 }
274 
275 /* generic inflate() run, where hex is the hexadecimal input data, what is the
276    text to include in an error message, step is how much input data to feed
277    inflate() on each call, or zero to feed it all, win is the window bits
278    parameter to inflateInit2(), len is the size of the output buffer, and err
279    is the error code expected from the first inflate() call (the second
280    inflate() call is expected to return Z_STREAM_END).  If win is 47, then
281    header information is collected with inflateGetHeader().  If a zlib stream
282    is looking for a dictionary, then an empty dictionary is provided.
283    inflate() is run until all of the input data is consumed. */
284 local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
285                int err)
286 {
287     int ret;
288     unsigned have;
289     unsigned char *in, *out;
290     z_stream strm, copy;
291     gz_header head;
292 
293     mem_setup(&strm);
294     strm.avail_in = 0;
295     strm.next_in = Z_NULL;
296     ret = inflateInit2(&strm, win);
297     if (ret != Z_OK) {
298         mem_done(&strm, what);
299         return;
300     }
301     out = malloc(len);                          assert(out != NULL);
302     if (win == 47) {
303         head.extra = out;
304         head.extra_max = len;
305         head.name = out;
306         head.name_max = len;
307         head.comment = out;
308         head.comm_max = len;
309         ret = inflateGetHeader(&strm, &head);   assert(ret == Z_OK);
310     }
311     in = h2b(hex, &have);                       assert(in != NULL);
312     if (step == 0 || step > have)
313         step = have;
314     strm.avail_in = step;
315     have -= step;
316     strm.next_in = in;
317     do {
318         strm.avail_out = len;
319         strm.next_out = out;
320         ret = inflate(&strm, Z_NO_FLUSH);       assert(err == 9 || ret == err);
321         if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
322             break;
323         if (ret == Z_NEED_DICT) {
324             ret = inflateSetDictionary(&strm, in, 1);
325                                                 assert(ret == Z_DATA_ERROR);
326             mem_limit(&strm, 1);
327             ret = inflateSetDictionary(&strm, out, 0);
328                                                 assert(ret == Z_MEM_ERROR);
329             mem_limit(&strm, 0);
330             ((struct inflate_state *)strm.state)->mode = DICT;
331             ret = inflateSetDictionary(&strm, out, 0);
332                                                 assert(ret == Z_OK);
333             ret = inflate(&strm, Z_NO_FLUSH);   assert(ret == Z_BUF_ERROR);
334         }
335         ret = inflateCopy(&copy, &strm);        assert(ret == Z_OK);
336         ret = inflateEnd(&copy);                assert(ret == Z_OK);
337         err = 9;                        /* don't care next time around */
338         have += strm.avail_in;
339         strm.avail_in = step > have ? have : step;
340         have -= strm.avail_in;
341     } while (strm.avail_in);
342     free(in);
343     free(out);
344     ret = inflateReset2(&strm, -8);             assert(ret == Z_OK);
345     ret = inflateEnd(&strm);                    assert(ret == Z_OK);
346     mem_done(&strm, what);
347 }
348 
349 /* cover all of the lines in inflate.c up to inflate() */
350 local void cover_support(void)
351 {
352     int ret;
353     z_stream strm;
354 
355     mem_setup(&strm);
356     strm.avail_in = 0;
357     strm.next_in = Z_NULL;
358     ret = inflateInit(&strm);                   assert(ret == Z_OK);
359     mem_used(&strm, "inflate init");
360     ret = inflatePrime(&strm, 5, 31);           assert(ret == Z_OK);
361     ret = inflatePrime(&strm, -1, 0);           assert(ret == Z_OK);
362     ret = inflateSetDictionary(&strm, Z_NULL, 0);
363                                                 assert(ret == Z_STREAM_ERROR);
364     ret = inflateEnd(&strm);                    assert(ret == Z_OK);
365     mem_done(&strm, "prime");
366 
367     inf("63 0", "force window allocation", 0, -15, 1, Z_OK);
368     inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK);
369     inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
370     inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
371     inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
372 
373     mem_setup(&strm);
374     strm.avail_in = 0;
375     strm.next_in = Z_NULL;
376     ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream));
377                                                 assert(ret == Z_VERSION_ERROR);
378     mem_done(&strm, "wrong version");
379 
380     strm.avail_in = 0;
381     strm.next_in = Z_NULL;
382     ret = inflateInit(&strm);                   assert(ret == Z_OK);
383     ret = inflateEnd(&strm);                    assert(ret == Z_OK);
384     fputs("inflate built-in memory routines\n", stderr);
385 }
386 
387 /* cover all inflate() header and trailer cases and code after inflate() */
388 local void cover_wrap(void)
389 {
390     int ret;
391     z_stream strm, copy;
392     unsigned char dict[257];
393 
394     ret = inflate(Z_NULL, 0);                   assert(ret == Z_STREAM_ERROR);
395     ret = inflateEnd(Z_NULL);                   assert(ret == Z_STREAM_ERROR);
396     ret = inflateCopy(Z_NULL, Z_NULL);          assert(ret == Z_STREAM_ERROR);
397     fputs("inflate bad parameters\n", stderr);
398 
399     inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
400     inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
401     inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR);
402     inf("8 99", "set window size from header", 0, 0, 0, Z_OK);
403     inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR);
404     inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END);
405     inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1,
406         Z_DATA_ERROR);
407     inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length",
408         0, 47, 0, Z_STREAM_END);
409     inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR);
410     inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT);
411     inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK);
412 
413     mem_setup(&strm);
414     strm.avail_in = 0;
415     strm.next_in = Z_NULL;
416     ret = inflateInit2(&strm, -8);
417     strm.avail_in = 2;
418     strm.next_in = (void *)"\x63";
419     strm.avail_out = 1;
420     strm.next_out = (void *)&ret;
421     mem_limit(&strm, 1);
422     ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
423     ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
424     mem_limit(&strm, 0);
425     memset(dict, 0, 257);
426     ret = inflateSetDictionary(&strm, dict, 257);
427                                                 assert(ret == Z_OK);
428     mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
429     ret = inflatePrime(&strm, 16, 0);           assert(ret == Z_OK);
430     strm.avail_in = 2;
431     strm.next_in = (void *)"\x80";
432     ret = inflateSync(&strm);                   assert(ret == Z_DATA_ERROR);
433     ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_STREAM_ERROR);
434     strm.avail_in = 4;
435     strm.next_in = (void *)"\0\0\xff\xff";
436     ret = inflateSync(&strm);                   assert(ret == Z_OK);
437     (void)inflateSyncPoint(&strm);
438     ret = inflateCopy(&copy, &strm);            assert(ret == Z_MEM_ERROR);
439     mem_limit(&strm, 0);
440     ret = inflateUndermine(&strm, 1);           assert(ret == Z_DATA_ERROR);
441     (void)inflateMark(&strm);
442     ret = inflateEnd(&strm);                    assert(ret == Z_OK);
443     mem_done(&strm, "miscellaneous, force memory errors");
444 }
445 
446 /* input and output functions for inflateBack() */
447 local unsigned pull(void *desc, unsigned char **buf)
448 {
449     static unsigned int next = 0;
450     static unsigned char dat[] = {0x63, 0, 2, 0};
451     struct inflate_state *state;
452 
453     if (desc == Z_NULL) {
454         next = 0;
455         return 0;   /* no input (already provided at next_in) */
456     }
457     state = (void *)((z_stream *)desc)->state;
458     if (state != Z_NULL)
459         state->mode = SYNC;     /* force an otherwise impossible situation */
460     return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
461 }
462 
463 local int push(void *desc, unsigned char *buf, unsigned len)
464 {
465     buf += len;
466     return desc != Z_NULL;      /* force error if desc not null */
467 }
468 
469 /* cover inflateBack() up to common deflate data cases and after those */
470 local void cover_back(void)
471 {
472     int ret;
473     z_stream strm;
474     unsigned char win[32768];
475 
476     ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
477                                                 assert(ret == Z_VERSION_ERROR);
478     ret = inflateBackInit(Z_NULL, 0, win);      assert(ret == Z_STREAM_ERROR);
479     ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
480                                                 assert(ret == Z_STREAM_ERROR);
481     ret = inflateBackEnd(Z_NULL);               assert(ret == Z_STREAM_ERROR);
482     fputs("inflateBack bad parameters\n", stderr);
483 
484     mem_setup(&strm);
485     ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
486     strm.avail_in = 2;
487     strm.next_in = (void *)"\x03";
488     ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
489                                                 assert(ret == Z_STREAM_END);
490         /* force output error */
491     strm.avail_in = 3;
492     strm.next_in = (void *)"\x63\x00";
493     ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
494                                                 assert(ret == Z_BUF_ERROR);
495         /* force mode error by mucking with state */
496     ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
497                                                 assert(ret == Z_STREAM_ERROR);
498     ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
499     mem_done(&strm, "inflateBack bad state");
500 
501     ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
502     ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
503     fputs("inflateBack built-in memory routines\n", stderr);
504 }
505 
506 /* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
507 local int try(char *hex, char *id, int err)
508 {
509     int ret;
510     unsigned len, size;
511     unsigned char *in, *out, *win;
512     char *prefix;
513     z_stream strm;
514 
515     /* convert to hex */
516     in = h2b(hex, &len);
517     assert(in != NULL);
518 
519     /* allocate work areas */
520     size = len << 3;
521     out = malloc(size);
522     assert(out != NULL);
523     win = malloc(32768);
524     assert(win != NULL);
525     prefix = malloc(strlen(id) + 6);
526     assert(prefix != NULL);
527 
528     /* first with inflate */
529     strcpy(prefix, id);
530     strcat(prefix, "-late");
531     mem_setup(&strm);
532     strm.avail_in = 0;
533     strm.next_in = Z_NULL;
534     ret = inflateInit2(&strm, err < 0 ? 47 : -15);
535     assert(ret == Z_OK);
536     strm.avail_in = len;
537     strm.next_in = in;
538     do {
539         strm.avail_out = size;
540         strm.next_out = out;
541         ret = inflate(&strm, Z_TREES);
542         assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR);
543         if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT)
544             break;
545     } while (strm.avail_in || strm.avail_out == 0);
546     if (err) {
547         assert(ret == Z_DATA_ERROR);
548         assert(strcmp(id, strm.msg) == 0);
549     }
550     inflateEnd(&strm);
551     mem_done(&strm, prefix);
552 
553     /* then with inflateBack */
554     if (err >= 0) {
555         strcpy(prefix, id);
556         strcat(prefix, "-back");
557         mem_setup(&strm);
558         ret = inflateBackInit(&strm, 15, win);
559         assert(ret == Z_OK);
560         strm.avail_in = len;
561         strm.next_in = in;
562         ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
563         assert(ret != Z_STREAM_ERROR);
564         if (err) {
565             assert(ret == Z_DATA_ERROR);
566             assert(strcmp(id, strm.msg) == 0);
567         }
568         inflateBackEnd(&strm);
569         mem_done(&strm, prefix);
570     }
571 
572     /* clean up */
573     free(prefix);
574     free(win);
575     free(out);
576     free(in);
577     return ret;
578 }
579 
580 /* cover deflate data cases in both inflate() and inflateBack() */
581 local void cover_inflate(void)
582 {
583     try("0 0 0 0 0", "invalid stored block lengths", 1);
584     try("3 0", "fixed", 0);
585     try("6", "invalid block type", 1);
586     try("1 1 0 fe ff 0", "stored", 0);
587     try("fc 0 0", "too many length or distance symbols", 1);
588     try("4 0 fe ff", "invalid code lengths set", 1);
589     try("4 0 24 49 0", "invalid bit length repeat", 1);
590     try("4 0 24 e9 ff ff", "invalid bit length repeat", 1);
591     try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1);
592     try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0",
593         "invalid literal/lengths set", 1);
594     try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1);
595     try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1);
596     try("2 7e ff ff", "invalid distance code", 1);
597     try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1);
598 
599     /* also trailer mismatch just in inflate() */
600     try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1);
601     try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1",
602         "incorrect length check", -1);
603     try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0);
604     try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f",
605         "long code", 0);
606     try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0);
607     try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c",
608         "long distance and extra", 0);
609     try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
610         "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0);
611     inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258,
612         Z_STREAM_END);
613     inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
614 }
615 
616 /* cover remaining lines in inftrees.c */
617 local void cover_trees(void)
618 {
619     int ret;
620     unsigned bits;
621     unsigned short lens[16], work[16];
622     code *next, table[ENOUGH_DISTS];
623 
624     /* we need to call inflate_table() directly in order to manifest not-
625        enough errors, since zlib insures that enough is always enough */
626     for (bits = 0; bits < 15; bits++)
627         lens[bits] = (unsigned short)(bits + 1);
628     lens[15] = 15;
629     next = table;
630     bits = 15;
631     ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
632                                                 assert(ret == 1);
633     next = table;
634     bits = 1;
635     ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
636                                                 assert(ret == 1);
637     fputs("inflate_table not enough errors\n", stderr);
638 }
639 
640 /* cover remaining inffast.c decoding and window copying */
641 local void cover_fast(void)
642 {
643     inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
644         " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
645     inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49"
646         " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258,
647         Z_DATA_ERROR);
648     inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258,
649         Z_DATA_ERROR);
650     inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258,
651         Z_DATA_ERROR);
652     inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0",
653         "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR);
654     inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK);
655     inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0",
656         "contiguous and wrap around window", 6, -8, 259, Z_OK);
657     inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259,
658         Z_STREAM_END);
659 }
660 
661 int main(void)
662 {
663     fprintf(stderr, "%s\n", zlibVersion());
664     cover_support();
665     cover_wrap();
666     cover_back();
667     cover_inflate();
668     cover_trees();
669     cover_fast();
670     return 0;
671 }
672