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