1230837Sdelphij/* infcover.c -- test zlib's inflate routines with full code coverage
2230837Sdelphij * Copyright (C) 2011 Mark Adler
3230837Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h
4230837Sdelphij */
5230837Sdelphij
6230837Sdelphij/* to use, do: ./configure --cover && make cover */
7230837Sdelphij
8230837Sdelphij#include <stdio.h>
9230837Sdelphij#include <stdlib.h>
10230837Sdelphij#include <string.h>
11230837Sdelphij#include <assert.h>
12230837Sdelphij#include "zlib.h"
13230837Sdelphij
14230837Sdelphij/* get definition of internal structure so we can mess with it (see pull()),
15230837Sdelphij   and so we can call inflate_trees() (see cover5()) */
16230837Sdelphij#define ZLIB_INTERNAL
17230837Sdelphij#include "inftrees.h"
18230837Sdelphij#include "inflate.h"
19230837Sdelphij
20230837Sdelphij#define local static
21230837Sdelphij
22230837Sdelphij/* -- memory tracking routines -- */
23230837Sdelphij
24230837Sdelphij/*
25230837Sdelphij   These memory tracking routines are provided to zlib and track all of zlib's
26230837Sdelphij   allocations and deallocations, check for LIFO operations, keep a current
27230837Sdelphij   and high water mark of total bytes requested, optionally set a limit on the
28230837Sdelphij   total memory that can be allocated, and when done check for memory leaks.
29230837Sdelphij
30230837Sdelphij   They are used as follows:
31230837Sdelphij
32230837Sdelphij   z_stream strm;
33230837Sdelphij   mem_setup(&strm)         initializes the memory tracking and sets the
34230837Sdelphij                            zalloc, zfree, and opaque members of strm to use
35230837Sdelphij                            memory tracking for all zlib operations on strm
36230837Sdelphij   mem_limit(&strm, limit)  sets a limit on the total bytes requested -- a
37230837Sdelphij                            request that exceeds this limit will result in an
38230837Sdelphij                            allocation failure (returns NULL) -- setting the
39230837Sdelphij                            limit to zero means no limit, which is the default
40230837Sdelphij                            after mem_setup()
41230837Sdelphij   mem_used(&strm, "msg")   prints to stderr "msg" and the total bytes used
42230837Sdelphij   mem_high(&strm, "msg")   prints to stderr "msg" and the high water mark
43230837Sdelphij   mem_done(&strm, "msg")   ends memory tracking, releases all allocations
44230837Sdelphij                            for the tracking as well as leaked zlib blocks, if
45230837Sdelphij                            any.  If there was anything unusual, such as leaked
46230837Sdelphij                            blocks, non-FIFO frees, or frees of addresses not
47230837Sdelphij                            allocated, then "msg" and information about the
48230837Sdelphij                            problem is printed to stderr.  If everything is
49230837Sdelphij                            normal, nothing is printed. mem_done resets the
50230837Sdelphij                            strm members to Z_NULL to use the default memory
51230837Sdelphij                            allocation routines on the next zlib initialization
52230837Sdelphij                            using strm.
53230837Sdelphij */
54230837Sdelphij
55230837Sdelphij/* these items are strung together in a linked list, one for each allocation */
56230837Sdelphijstruct mem_item {
57230837Sdelphij    void *ptr;                  /* pointer to allocated memory */
58230837Sdelphij    size_t size;                /* requested size of allocation */
59230837Sdelphij    struct mem_item *next;      /* pointer to next item in list, or NULL */
60230837Sdelphij};
61230837Sdelphij
62230837Sdelphij/* this structure is at the root of the linked list, and tracks statistics */
63230837Sdelphijstruct mem_zone {
64230837Sdelphij    struct mem_item *first;     /* pointer to first item in list, or NULL */
65230837Sdelphij    size_t total, highwater;    /* total allocations, and largest total */
66230837Sdelphij    size_t limit;               /* memory allocation limit, or 0 if no limit */
67230837Sdelphij    int notlifo, rogue;         /* counts of non-LIFO frees and rogue frees */
68230837Sdelphij};
69230837Sdelphij
70230837Sdelphij/* memory allocation routine to pass to zlib */
71230837Sdelphijlocal void *mem_alloc(void *mem, unsigned count, unsigned size)
72230837Sdelphij{
73230837Sdelphij    void *ptr;
74230837Sdelphij    struct mem_item *item;
75230837Sdelphij    struct mem_zone *zone = mem;
76230837Sdelphij    size_t len = count * (size_t)size;
77230837Sdelphij
78230837Sdelphij    /* induced allocation failure */
79230837Sdelphij    if (zone == NULL || (zone->limit && zone->total + len > zone->limit))
80230837Sdelphij        return NULL;
81230837Sdelphij
82230837Sdelphij    /* perform allocation using the standard library, fill memory with a
83230837Sdelphij       non-zero value to make sure that the code isn't depending on zeros */
84230837Sdelphij    ptr = malloc(len);
85230837Sdelphij    if (ptr == NULL)
86230837Sdelphij        return NULL;
87230837Sdelphij    memset(ptr, 0xa5, len);
88230837Sdelphij
89230837Sdelphij    /* create a new item for the list */
90230837Sdelphij    item = malloc(sizeof(struct mem_item));
91230837Sdelphij    if (item == NULL) {
92230837Sdelphij        free(ptr);
93230837Sdelphij        return NULL;
94230837Sdelphij    }
95230837Sdelphij    item->ptr = ptr;
96230837Sdelphij    item->size = len;
97230837Sdelphij
98230837Sdelphij    /* insert item at the beginning of the list */
99230837Sdelphij    item->next = zone->first;
100230837Sdelphij    zone->first = item;
101230837Sdelphij
102230837Sdelphij    /* update the statistics */
103230837Sdelphij    zone->total += item->size;
104230837Sdelphij    if (zone->total > zone->highwater)
105230837Sdelphij        zone->highwater = zone->total;
106230837Sdelphij
107230837Sdelphij    /* return the allocated memory */
108230837Sdelphij    return ptr;
109230837Sdelphij}
110230837Sdelphij
111230837Sdelphij/* memory free routine to pass to zlib */
112230837Sdelphijlocal void mem_free(void *mem, void *ptr)
113230837Sdelphij{
114230837Sdelphij    struct mem_item *item, *next;
115230837Sdelphij    struct mem_zone *zone = mem;
116230837Sdelphij
117230837Sdelphij    /* if no zone, just do a free */
118230837Sdelphij    if (zone == NULL) {
119230837Sdelphij        free(ptr);
120230837Sdelphij        return;
121230837Sdelphij    }
122230837Sdelphij
123230837Sdelphij    /* point next to the item that matches ptr, or NULL if not found -- remove
124230837Sdelphij       the item from the linked list if found */
125230837Sdelphij    next = zone->first;
126230837Sdelphij    if (next) {
127230837Sdelphij        if (next->ptr == ptr)
128230837Sdelphij            zone->first = next->next;   /* first one is it, remove from list */
129230837Sdelphij        else {
130230837Sdelphij            do {                        /* search the linked list */
131230837Sdelphij                item = next;
132230837Sdelphij                next = item->next;
133230837Sdelphij            } while (next != NULL && next->ptr != ptr);
134230837Sdelphij            if (next) {                 /* if found, remove from linked list */
135230837Sdelphij                item->next = next->next;
136230837Sdelphij                zone->notlifo++;        /* not a LIFO free */
137230837Sdelphij            }
138230837Sdelphij
139230837Sdelphij        }
140230837Sdelphij    }
141230837Sdelphij
142230837Sdelphij    /* if found, update the statistics and free the item */
143230837Sdelphij    if (next) {
144230837Sdelphij        zone->total -= next->size;
145230837Sdelphij        free(next);
146230837Sdelphij    }
147230837Sdelphij
148230837Sdelphij    /* if not found, update the rogue count */
149230837Sdelphij    else
150230837Sdelphij        zone->rogue++;
151230837Sdelphij
152230837Sdelphij    /* in any case, do the requested free with the standard library function */
153230837Sdelphij    free(ptr);
154230837Sdelphij}
155230837Sdelphij
156230837Sdelphij/* set up a controlled memory allocation space for monitoring, set the stream
157230837Sdelphij   parameters to the controlled routines, with opaque pointing to the space */
158230837Sdelphijlocal void mem_setup(z_stream *strm)
159230837Sdelphij{
160230837Sdelphij    struct mem_zone *zone;
161230837Sdelphij
162230837Sdelphij    zone = malloc(sizeof(struct mem_zone));
163230837Sdelphij    assert(zone != NULL);
164230837Sdelphij    zone->first = NULL;
165230837Sdelphij    zone->total = 0;
166230837Sdelphij    zone->highwater = 0;
167230837Sdelphij    zone->limit = 0;
168230837Sdelphij    zone->notlifo = 0;
169230837Sdelphij    zone->rogue = 0;
170230837Sdelphij    strm->opaque = zone;
171230837Sdelphij    strm->zalloc = mem_alloc;
172230837Sdelphij    strm->zfree = mem_free;
173230837Sdelphij}
174230837Sdelphij
175230837Sdelphij/* set a limit on the total memory allocation, or 0 to remove the limit */
176230837Sdelphijlocal void mem_limit(z_stream *strm, size_t limit)
177230837Sdelphij{
178230837Sdelphij    struct mem_zone *zone = strm->opaque;
179230837Sdelphij
180230837Sdelphij    zone->limit = limit;
181230837Sdelphij}
182230837Sdelphij
183230837Sdelphij/* show the current total requested allocations in bytes */
184230837Sdelphijlocal void mem_used(z_stream *strm, char *prefix)
185230837Sdelphij{
186230837Sdelphij    struct mem_zone *zone = strm->opaque;
187230837Sdelphij
188230837Sdelphij    fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total);
189230837Sdelphij}
190230837Sdelphij
191230837Sdelphij/* show the high water allocation in bytes */
192230837Sdelphijlocal void mem_high(z_stream *strm, char *prefix)
193230837Sdelphij{
194230837Sdelphij    struct mem_zone *zone = strm->opaque;
195230837Sdelphij
196230837Sdelphij    fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater);
197230837Sdelphij}
198230837Sdelphij
199230837Sdelphij/* release the memory allocation zone -- if there are any surprises, notify */
200230837Sdelphijlocal void mem_done(z_stream *strm, char *prefix)
201230837Sdelphij{
202230837Sdelphij    int count = 0;
203230837Sdelphij    struct mem_item *item, *next;
204230837Sdelphij    struct mem_zone *zone = strm->opaque;
205230837Sdelphij
206230837Sdelphij    /* show high water mark */
207230837Sdelphij    mem_high(strm, prefix);
208230837Sdelphij
209230837Sdelphij    /* free leftover allocations and item structures, if any */
210230837Sdelphij    item = zone->first;
211230837Sdelphij    while (item != NULL) {
212230837Sdelphij        free(item->ptr);
213230837Sdelphij        next = item->next;
214230837Sdelphij        free(item);
215230837Sdelphij        item = next;
216230837Sdelphij        count++;
217230837Sdelphij    }
218230837Sdelphij
219230837Sdelphij    /* issue alerts about anything unexpected */
220230837Sdelphij    if (count || zone->total)
221230837Sdelphij        fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n",
222230837Sdelphij                prefix, zone->total, count);
223230837Sdelphij    if (zone->notlifo)
224230837Sdelphij        fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo);
225230837Sdelphij    if (zone->rogue)
226230837Sdelphij        fprintf(stderr, "** %s: %d frees not recognized\n",
227230837Sdelphij                prefix, zone->rogue);
228230837Sdelphij
229230837Sdelphij    /* free the zone and delete from the stream */
230230837Sdelphij    free(zone);
231230837Sdelphij    strm->opaque = Z_NULL;
232230837Sdelphij    strm->zalloc = Z_NULL;
233230837Sdelphij    strm->zfree = Z_NULL;
234230837Sdelphij}
235230837Sdelphij
236230837Sdelphij/* -- inflate test routines -- */
237230837Sdelphij
238230837Sdelphij/* Decode a hexadecimal string, set *len to length, in[] to the bytes.  This
239230837Sdelphij   decodes liberally, in that hex digits can be adjacent, in which case two in
240230837Sdelphij   a row writes a byte.  Or they can delimited by any non-hex character, where
241230837Sdelphij   the delimiters are ignored except when a single hex digit is followed by a
242230837Sdelphij   delimiter in which case that single digit writes a byte.  The returned
243230837Sdelphij   data is allocated and must eventually be freed.  NULL is returned if out of
244230837Sdelphij   memory.  If the length is not needed, then len can be NULL. */
245230837Sdelphijlocal unsigned char *h2b(const char *hex, unsigned *len)
246230837Sdelphij{
247230837Sdelphij    unsigned char *in;
248230837Sdelphij    unsigned next, val;
249230837Sdelphij
250230837Sdelphij    in = malloc((strlen(hex) + 1) >> 1);
251230837Sdelphij    if (in == NULL)
252230837Sdelphij        return NULL;
253230837Sdelphij    next = 0;
254230837Sdelphij    val = 1;
255230837Sdelphij    do {
256230837Sdelphij        if (*hex >= '0' && *hex <= '9')
257230837Sdelphij            val = (val << 4) + *hex - '0';
258230837Sdelphij        else if (*hex >= 'A' && *hex <= 'F')
259230837Sdelphij            val = (val << 4) + *hex - 'A' + 10;
260230837Sdelphij        else if (*hex >= 'a' && *hex <= 'f')
261230837Sdelphij            val = (val << 4) + *hex - 'a' + 10;
262230837Sdelphij        else if (val != 1 && val < 32)  /* one digit followed by delimiter */
263230837Sdelphij            val += 240;                 /* make it look like two digits */
264230837Sdelphij        if (val > 255) {                /* have two digits */
265230837Sdelphij            in[next++] = val & 0xff;    /* save the decoded byte */
266230837Sdelphij            val = 1;                    /* start over */
267230837Sdelphij        }
268230837Sdelphij    } while (*hex++);       /* go through the loop with the terminating null */
269230837Sdelphij    if (len != NULL)
270230837Sdelphij        *len = next;
271230837Sdelphij    in = reallocf(in, next);
272230837Sdelphij    return in;
273230837Sdelphij}
274230837Sdelphij
275230837Sdelphij/* generic inflate() run, where hex is the hexadecimal input data, what is the
276230837Sdelphij   text to include in an error message, step is how much input data to feed
277230837Sdelphij   inflate() on each call, or zero to feed it all, win is the window bits
278230837Sdelphij   parameter to inflateInit2(), len is the size of the output buffer, and err
279230837Sdelphij   is the error code expected from the first inflate() call (the second
280230837Sdelphij   inflate() call is expected to return Z_STREAM_END).  If win is 47, then
281230837Sdelphij   header information is collected with inflateGetHeader().  If a zlib stream
282230837Sdelphij   is looking for a dictionary, then an empty dictionary is provided.
283230837Sdelphij   inflate() is run until all of the input data is consumed. */
284230837Sdelphijlocal void inf(char *hex, char *what, unsigned step, int win, unsigned len,
285230837Sdelphij               int err)
286230837Sdelphij{
287230837Sdelphij    int ret;
288230837Sdelphij    unsigned have;
289230837Sdelphij    unsigned char *in, *out;
290230837Sdelphij    z_stream strm, copy;
291230837Sdelphij    gz_header head;
292230837Sdelphij
293230837Sdelphij    mem_setup(&strm);
294230837Sdelphij    strm.avail_in = 0;
295230837Sdelphij    strm.next_in = Z_NULL;
296230837Sdelphij    ret = inflateInit2(&strm, win);
297230837Sdelphij    if (ret != Z_OK) {
298230837Sdelphij        mem_done(&strm, what);
299230837Sdelphij        return;
300230837Sdelphij    }
301230837Sdelphij    out = malloc(len);                          assert(out != NULL);
302230837Sdelphij    if (win == 47) {
303230837Sdelphij        head.extra = out;
304230837Sdelphij        head.extra_max = len;
305230837Sdelphij        head.name = out;
306230837Sdelphij        head.name_max = len;
307230837Sdelphij        head.comment = out;
308230837Sdelphij        head.comm_max = len;
309230837Sdelphij        ret = inflateGetHeader(&strm, &head);   assert(ret == Z_OK);
310230837Sdelphij    }
311230837Sdelphij    in = h2b(hex, &have);                       assert(in != NULL);
312230837Sdelphij    if (step == 0 || step > have)
313230837Sdelphij        step = have;
314230837Sdelphij    strm.avail_in = step;
315230837Sdelphij    have -= step;
316230837Sdelphij    strm.next_in = in;
317230837Sdelphij    do {
318230837Sdelphij        strm.avail_out = len;
319230837Sdelphij        strm.next_out = out;
320230837Sdelphij        ret = inflate(&strm, Z_NO_FLUSH);       assert(err == 9 || ret == err);
321230837Sdelphij        if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
322230837Sdelphij            break;
323230837Sdelphij        if (ret == Z_NEED_DICT) {
324230837Sdelphij            ret = inflateSetDictionary(&strm, in, 1);
325230837Sdelphij                                                assert(ret == Z_DATA_ERROR);
326230837Sdelphij            mem_limit(&strm, 1);
327230837Sdelphij            ret = inflateSetDictionary(&strm, out, 0);
328230837Sdelphij                                                assert(ret == Z_MEM_ERROR);
329230837Sdelphij            mem_limit(&strm, 0);
330230837Sdelphij            ((struct inflate_state *)strm.state)->mode = DICT;
331230837Sdelphij            ret = inflateSetDictionary(&strm, out, 0);
332230837Sdelphij                                                assert(ret == Z_OK);
333230837Sdelphij            ret = inflate(&strm, Z_NO_FLUSH);   assert(ret == Z_BUF_ERROR);
334230837Sdelphij        }
335230837Sdelphij        ret = inflateCopy(&copy, &strm);        assert(ret == Z_OK);
336230837Sdelphij        ret = inflateEnd(&copy);                assert(ret == Z_OK);
337230837Sdelphij        err = 9;                        /* don't care next time around */
338230837Sdelphij        have += strm.avail_in;
339230837Sdelphij        strm.avail_in = step > have ? have : step;
340230837Sdelphij        have -= strm.avail_in;
341230837Sdelphij    } while (strm.avail_in);
342230837Sdelphij    free(in);
343230837Sdelphij    free(out);
344230837Sdelphij    ret = inflateReset2(&strm, -8);             assert(ret == Z_OK);
345230837Sdelphij    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
346230837Sdelphij    mem_done(&strm, what);
347230837Sdelphij}
348230837Sdelphij
349230837Sdelphij/* cover all of the lines in inflate.c up to inflate() */
350230837Sdelphijlocal void cover_support(void)
351230837Sdelphij{
352230837Sdelphij    int ret;
353230837Sdelphij    z_stream strm;
354230837Sdelphij
355230837Sdelphij    mem_setup(&strm);
356230837Sdelphij    strm.avail_in = 0;
357230837Sdelphij    strm.next_in = Z_NULL;
358230837Sdelphij    ret = inflateInit(&strm);                   assert(ret == Z_OK);
359230837Sdelphij    mem_used(&strm, "inflate init");
360230837Sdelphij    ret = inflatePrime(&strm, 5, 31);           assert(ret == Z_OK);
361230837Sdelphij    ret = inflatePrime(&strm, -1, 0);           assert(ret == Z_OK);
362230837Sdelphij    ret = inflateSetDictionary(&strm, Z_NULL, 0);
363230837Sdelphij                                                assert(ret == Z_STREAM_ERROR);
364230837Sdelphij    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
365230837Sdelphij    mem_done(&strm, "prime");
366230837Sdelphij
367230837Sdelphij    inf("63 0", "force window allocation", 0, -15, 1, Z_OK);
368230837Sdelphij    inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK);
369230837Sdelphij    inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
370230837Sdelphij    inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
371230837Sdelphij    inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
372230837Sdelphij
373230837Sdelphij    mem_setup(&strm);
374230837Sdelphij    strm.avail_in = 0;
375230837Sdelphij    strm.next_in = Z_NULL;
376230837Sdelphij    ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream));
377230837Sdelphij                                                assert(ret == Z_VERSION_ERROR);
378230837Sdelphij    mem_done(&strm, "wrong version");
379230837Sdelphij
380230837Sdelphij    strm.avail_in = 0;
381230837Sdelphij    strm.next_in = Z_NULL;
382230837Sdelphij    ret = inflateInit(&strm);                   assert(ret == Z_OK);
383230837Sdelphij    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
384230837Sdelphij    fputs("inflate built-in memory routines\n", stderr);
385230837Sdelphij}
386230837Sdelphij
387230837Sdelphij/* cover all inflate() header and trailer cases and code after inflate() */
388230837Sdelphijlocal void cover_wrap(void)
389230837Sdelphij{
390230837Sdelphij    int ret;
391230837Sdelphij    z_stream strm, copy;
392230837Sdelphij    unsigned char dict[257];
393230837Sdelphij
394230837Sdelphij    ret = inflate(Z_NULL, 0);                   assert(ret == Z_STREAM_ERROR);
395230837Sdelphij    ret = inflateEnd(Z_NULL);                   assert(ret == Z_STREAM_ERROR);
396230837Sdelphij    ret = inflateCopy(Z_NULL, Z_NULL);          assert(ret == Z_STREAM_ERROR);
397230837Sdelphij    fputs("inflate bad parameters\n", stderr);
398230837Sdelphij
399230837Sdelphij    inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
400230837Sdelphij    inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
401230837Sdelphij    inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR);
402230837Sdelphij    inf("8 99", "set window size from header", 0, 0, 0, Z_OK);
403230837Sdelphij    inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR);
404230837Sdelphij    inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END);
405230837Sdelphij    inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1,
406230837Sdelphij        Z_DATA_ERROR);
407230837Sdelphij    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",
408230837Sdelphij        0, 47, 0, Z_STREAM_END);
409230837Sdelphij    inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR);
410230837Sdelphij    inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT);
411230837Sdelphij    inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK);
412230837Sdelphij
413230837Sdelphij    mem_setup(&strm);
414230837Sdelphij    strm.avail_in = 0;
415230837Sdelphij    strm.next_in = Z_NULL;
416230837Sdelphij    ret = inflateInit2(&strm, -8);
417230837Sdelphij    strm.avail_in = 2;
418230837Sdelphij    strm.next_in = (void *)"\x63";
419230837Sdelphij    strm.avail_out = 1;
420230837Sdelphij    strm.next_out = (void *)&ret;
421230837Sdelphij    mem_limit(&strm, 1);
422230837Sdelphij    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
423230837Sdelphij    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
424230837Sdelphij    mem_limit(&strm, 0);
425230837Sdelphij    memset(dict, 0, 257);
426230837Sdelphij    ret = inflateSetDictionary(&strm, dict, 257);
427230837Sdelphij                                                assert(ret == Z_OK);
428230837Sdelphij    mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
429230837Sdelphij    ret = inflatePrime(&strm, 16, 0);           assert(ret == Z_OK);
430230837Sdelphij    strm.avail_in = 2;
431230837Sdelphij    strm.next_in = (void *)"\x80";
432230837Sdelphij    ret = inflateSync(&strm);                   assert(ret == Z_DATA_ERROR);
433230837Sdelphij    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_STREAM_ERROR);
434230837Sdelphij    strm.avail_in = 4;
435230837Sdelphij    strm.next_in = (void *)"\0\0\xff\xff";
436230837Sdelphij    ret = inflateSync(&strm);                   assert(ret == Z_OK);
437230837Sdelphij    (void)inflateSyncPoint(&strm);
438230837Sdelphij    ret = inflateCopy(&copy, &strm);            assert(ret == Z_MEM_ERROR);
439230837Sdelphij    mem_limit(&strm, 0);
440230837Sdelphij    ret = inflateUndermine(&strm, 1);           assert(ret == Z_DATA_ERROR);
441230837Sdelphij    (void)inflateMark(&strm);
442230837Sdelphij    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
443230837Sdelphij    mem_done(&strm, "miscellaneous, force memory errors");
444230837Sdelphij}
445230837Sdelphij
446230837Sdelphij/* input and output functions for inflateBack() */
447230837Sdelphijlocal unsigned pull(void *desc, unsigned char **buf)
448230837Sdelphij{
449230837Sdelphij    static unsigned int next = 0;
450230837Sdelphij    static unsigned char dat[] = {0x63, 0, 2, 0};
451230837Sdelphij    struct inflate_state *state;
452230837Sdelphij
453230837Sdelphij    if (desc == Z_NULL) {
454230837Sdelphij        next = 0;
455230837Sdelphij        return 0;   /* no input (already provided at next_in) */
456230837Sdelphij    }
457230837Sdelphij    state = (void *)((z_stream *)desc)->state;
458230837Sdelphij    if (state != Z_NULL)
459230837Sdelphij        state->mode = SYNC;     /* force an otherwise impossible situation */
460230837Sdelphij    return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
461230837Sdelphij}
462230837Sdelphij
463230837Sdelphijlocal int push(void *desc, unsigned char *buf, unsigned len)
464230837Sdelphij{
465230837Sdelphij    buf += len;
466230837Sdelphij    return desc != Z_NULL;      /* force error if desc not null */
467230837Sdelphij}
468230837Sdelphij
469230837Sdelphij/* cover inflateBack() up to common deflate data cases and after those */
470230837Sdelphijlocal void cover_back(void)
471230837Sdelphij{
472230837Sdelphij    int ret;
473230837Sdelphij    z_stream strm;
474230837Sdelphij    unsigned char win[32768];
475230837Sdelphij
476230837Sdelphij    ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
477230837Sdelphij                                                assert(ret == Z_VERSION_ERROR);
478230837Sdelphij    ret = inflateBackInit(Z_NULL, 0, win);      assert(ret == Z_STREAM_ERROR);
479230837Sdelphij    ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
480230837Sdelphij                                                assert(ret == Z_STREAM_ERROR);
481230837Sdelphij    ret = inflateBackEnd(Z_NULL);               assert(ret == Z_STREAM_ERROR);
482230837Sdelphij    fputs("inflateBack bad parameters\n", stderr);
483230837Sdelphij
484230837Sdelphij    mem_setup(&strm);
485230837Sdelphij    ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
486230837Sdelphij    strm.avail_in = 2;
487230837Sdelphij    strm.next_in = (void *)"\x03";
488230837Sdelphij    ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
489230837Sdelphij                                                assert(ret == Z_STREAM_END);
490230837Sdelphij        /* force output error */
491230837Sdelphij    strm.avail_in = 3;
492230837Sdelphij    strm.next_in = (void *)"\x63\x00";
493230837Sdelphij    ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
494230837Sdelphij                                                assert(ret == Z_BUF_ERROR);
495230837Sdelphij        /* force mode error by mucking with state */
496230837Sdelphij    ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
497230837Sdelphij                                                assert(ret == Z_STREAM_ERROR);
498230837Sdelphij    ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
499230837Sdelphij    mem_done(&strm, "inflateBack bad state");
500230837Sdelphij
501230837Sdelphij    ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
502230837Sdelphij    ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
503230837Sdelphij    fputs("inflateBack built-in memory routines\n", stderr);
504230837Sdelphij}
505230837Sdelphij
506230837Sdelphij/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
507230837Sdelphijlocal int try(char *hex, char *id, int err)
508230837Sdelphij{
509230837Sdelphij    int ret;
510230837Sdelphij    unsigned len, size;
511230837Sdelphij    unsigned char *in, *out, *win;
512230837Sdelphij    char *prefix;
513230837Sdelphij    z_stream strm;
514230837Sdelphij
515230837Sdelphij    /* convert to hex */
516230837Sdelphij    in = h2b(hex, &len);
517230837Sdelphij    assert(in != NULL);
518230837Sdelphij
519230837Sdelphij    /* allocate work areas */
520230837Sdelphij    size = len << 3;
521230837Sdelphij    out = malloc(size);
522230837Sdelphij    assert(out != NULL);
523230837Sdelphij    win = malloc(32768);
524230837Sdelphij    assert(win != NULL);
525230837Sdelphij    prefix = malloc(strlen(id) + 6);
526230837Sdelphij    assert(prefix != NULL);
527230837Sdelphij
528230837Sdelphij    /* first with inflate */
529230837Sdelphij    strcpy(prefix, id);
530230837Sdelphij    strcat(prefix, "-late");
531230837Sdelphij    mem_setup(&strm);
532230837Sdelphij    strm.avail_in = 0;
533230837Sdelphij    strm.next_in = Z_NULL;
534230837Sdelphij    ret = inflateInit2(&strm, err < 0 ? 47 : -15);
535230837Sdelphij    assert(ret == Z_OK);
536230837Sdelphij    strm.avail_in = len;
537230837Sdelphij    strm.next_in = in;
538230837Sdelphij    do {
539230837Sdelphij        strm.avail_out = size;
540230837Sdelphij        strm.next_out = out;
541230837Sdelphij        ret = inflate(&strm, Z_TREES);
542230837Sdelphij        assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR);
543230837Sdelphij        if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT)
544230837Sdelphij            break;
545230837Sdelphij    } while (strm.avail_in || strm.avail_out == 0);
546230837Sdelphij    if (err) {
547230837Sdelphij        assert(ret == Z_DATA_ERROR);
548230837Sdelphij        assert(strcmp(id, strm.msg) == 0);
549230837Sdelphij    }
550230837Sdelphij    inflateEnd(&strm);
551230837Sdelphij    mem_done(&strm, prefix);
552230837Sdelphij
553230837Sdelphij    /* then with inflateBack */
554230837Sdelphij    if (err >= 0) {
555230837Sdelphij        strcpy(prefix, id);
556230837Sdelphij        strcat(prefix, "-back");
557230837Sdelphij        mem_setup(&strm);
558230837Sdelphij        ret = inflateBackInit(&strm, 15, win);
559230837Sdelphij        assert(ret == Z_OK);
560230837Sdelphij        strm.avail_in = len;
561230837Sdelphij        strm.next_in = in;
562230837Sdelphij        ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
563230837Sdelphij        assert(ret != Z_STREAM_ERROR);
564230837Sdelphij        if (err) {
565230837Sdelphij            assert(ret == Z_DATA_ERROR);
566230837Sdelphij            assert(strcmp(id, strm.msg) == 0);
567230837Sdelphij        }
568230837Sdelphij        inflateBackEnd(&strm);
569230837Sdelphij        mem_done(&strm, prefix);
570230837Sdelphij    }
571230837Sdelphij
572230837Sdelphij    /* clean up */
573230837Sdelphij    free(prefix);
574230837Sdelphij    free(win);
575230837Sdelphij    free(out);
576230837Sdelphij    free(in);
577230837Sdelphij    return ret;
578230837Sdelphij}
579230837Sdelphij
580230837Sdelphij/* cover deflate data cases in both inflate() and inflateBack() */
581230837Sdelphijlocal void cover_inflate(void)
582230837Sdelphij{
583230837Sdelphij    try("0 0 0 0 0", "invalid stored block lengths", 1);
584230837Sdelphij    try("3 0", "fixed", 0);
585230837Sdelphij    try("6", "invalid block type", 1);
586230837Sdelphij    try("1 1 0 fe ff 0", "stored", 0);
587230837Sdelphij    try("fc 0 0", "too many length or distance symbols", 1);
588230837Sdelphij    try("4 0 fe ff", "invalid code lengths set", 1);
589230837Sdelphij    try("4 0 24 49 0", "invalid bit length repeat", 1);
590230837Sdelphij    try("4 0 24 e9 ff ff", "invalid bit length repeat", 1);
591230837Sdelphij    try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1);
592230837Sdelphij    try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0",
593230837Sdelphij        "invalid literal/lengths set", 1);
594230837Sdelphij    try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1);
595230837Sdelphij    try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1);
596230837Sdelphij    try("2 7e ff ff", "invalid distance code", 1);
597230837Sdelphij    try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1);
598230837Sdelphij
599230837Sdelphij    /* also trailer mismatch just in inflate() */
600230837Sdelphij    try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1);
601230837Sdelphij    try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1",
602230837Sdelphij        "incorrect length check", -1);
603230837Sdelphij    try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0);
604230837Sdelphij    try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f",
605230837Sdelphij        "long code", 0);
606230837Sdelphij    try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0);
607230837Sdelphij    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",
608230837Sdelphij        "long distance and extra", 0);
609230837Sdelphij    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 "
610230837Sdelphij        "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0);
611230837Sdelphij    inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258,
612230837Sdelphij        Z_STREAM_END);
613230837Sdelphij    inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
614230837Sdelphij}
615230837Sdelphij
616230837Sdelphij/* cover remaining lines in inftrees.c */
617230837Sdelphijlocal void cover_trees(void)
618230837Sdelphij{
619230837Sdelphij    int ret;
620230837Sdelphij    unsigned bits;
621230837Sdelphij    unsigned short lens[16], work[16];
622230837Sdelphij    code *next, table[ENOUGH_DISTS];
623230837Sdelphij
624230837Sdelphij    /* we need to call inflate_table() directly in order to manifest not-
625230837Sdelphij       enough errors, since zlib insures that enough is always enough */
626230837Sdelphij    for (bits = 0; bits < 15; bits++)
627230837Sdelphij        lens[bits] = (unsigned short)(bits + 1);
628230837Sdelphij    lens[15] = 15;
629230837Sdelphij    next = table;
630230837Sdelphij    bits = 15;
631230837Sdelphij    ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
632230837Sdelphij                                                assert(ret == 1);
633230837Sdelphij    next = table;
634230837Sdelphij    bits = 1;
635230837Sdelphij    ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
636230837Sdelphij                                                assert(ret == 1);
637230837Sdelphij    fputs("inflate_table not enough errors\n", stderr);
638230837Sdelphij}
639230837Sdelphij
640230837Sdelphij/* cover remaining inffast.c decoding and window copying */
641230837Sdelphijlocal void cover_fast(void)
642230837Sdelphij{
643230837Sdelphij    inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
644230837Sdelphij        " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
645230837Sdelphij    inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49"
646230837Sdelphij        " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258,
647230837Sdelphij        Z_DATA_ERROR);
648230837Sdelphij    inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258,
649230837Sdelphij        Z_DATA_ERROR);
650230837Sdelphij    inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258,
651230837Sdelphij        Z_DATA_ERROR);
652230837Sdelphij    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",
653230837Sdelphij        "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR);
654230837Sdelphij    inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK);
655230837Sdelphij    inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0",
656230837Sdelphij        "contiguous and wrap around window", 6, -8, 259, Z_OK);
657230837Sdelphij    inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259,
658230837Sdelphij        Z_STREAM_END);
659230837Sdelphij}
660230837Sdelphij
661230837Sdelphijint main(void)
662230837Sdelphij{
663230837Sdelphij    fprintf(stderr, "%s\n", zlibVersion());
664230837Sdelphij    cover_support();
665230837Sdelphij    cover_wrap();
666230837Sdelphij    cover_back();
667230837Sdelphij    cover_inflate();
668230837Sdelphij    cover_trees();
669230837Sdelphij    cover_fast();
670230837Sdelphij    return 0;
671230837Sdelphij}
672