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