/* infcover.c -- test zlib's inflate routines with full code coverage *Copyright(C)2011,2016MarkAdler *Forconditionsofdistributionanduse,seecopyrightnoticeinzlib.h
*/
/* to use, do: ./configure --cover && make cover */
/* get definition of internal structure so we can mess with it (see pull()),
and so we can call inflate_trees() (see cover5()) */ #define ZLIB_INTERNAL #include"inftrees.h" #include"inflate.h"
/* these items are strung together in a linked list, one for each allocation */ struct mem_item { void *ptr; /* pointer to allocated memory */
size_t size; /* requested size of allocation */ struct mem_item *next; /* pointer to next item in list, or NULL */
};
/* this structure is at the root of the linked list, and tracks statistics */ struct mem_zone { struct mem_item *first; /* pointer to first item in list, or NULL */
size_t total, highwater; /* total allocations, and largest total */
size_t limit; /* memory allocation limit, or 0 if no limit */ int notlifo, rogue; /* counts of non-LIFO frees and rogue frees */
};
/* memory allocation routine to pass to zlib */
local void *mem_alloc(void *mem, unsigned count, unsigned size)
{ void *ptr; struct mem_item *item; struct mem_zone *zone = mem;
size_t len = count * (size_t)size;
/* induced allocation failure */ if (zone == NULL || (zone->limit && zone->total + len > zone->limit)) return NULL;
/* perform allocation using the standard library, fill memory with a
non-zero value to make sure that the code isn't depending on zeros */
ptr = malloc(len); if (ptr == NULL) return NULL;
memset(ptr, 0xa5, len);
/* create a new item for the list */
item = malloc(sizeof(struct mem_item)); if (item == NULL) {
free(ptr); return NULL;
}
item->ptr = ptr;
item->size = len;
/* insert item at the beginning of the list */
item->next = zone->first;
zone->first = item;
/* update the statistics */
zone->total += item->size; if (zone->total > zone->highwater)
zone->highwater = zone->total;
/* return the allocated memory */ return ptr;
}
/* memory free routine to pass to zlib */
local void mem_free(void *mem, void *ptr)
{ struct mem_item *item, *next; struct mem_zone *zone = mem;
/* if no zone, just do a free */ if (zone == NULL) {
free(ptr); return;
}
/* point next to the item that matches ptr, or NULL if not found -- remove
the item from the linked list if found */
next = zone->first; if (next) { if (next->ptr == ptr)
zone->first = next->next; /* first one is it, remove from list */ else { do { /* search the linked list */
item = next;
next = item->next;
} while (next != NULL && next->ptr != ptr); if (next) { /* if found, remove from linked list */
item->next = next->next;
zone->notlifo++; /* not a LIFO free */
}
}
}
/* if found, update the statistics and free the item */ if (next) {
zone->total -= next->size;
free(next);
}
/* if not found, update the rogue count */ else
zone->rogue++;
/* in any case, do the requested free with the standard library function */
free(ptr);
}
/* set up a controlled memory allocation space for monitoring, set the stream
parameters to the controlled routines, with opaque pointing to the space */
local void mem_setup(z_stream *strm)
{ struct mem_zone *zone;
/* set a limit on the total memory allocation, or 0 to remove the limit */
local void mem_limit(z_stream *strm, size_t limit)
{ struct mem_zone *zone = strm->opaque;
zone->limit = limit;
}
/* show the current total requested allocations in bytes */
local void mem_used(z_stream *strm, char *prefix)
{ struct mem_zone *zone = strm->opaque;
/* show the high water allocation in bytes */
local void mem_high(z_stream *strm, char *prefix)
{ struct mem_zone *zone = strm->opaque;
fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater);
}
/* release the memory allocation zone -- if there are any surprises, notify */
local void mem_done(z_stream *strm, char *prefix)
{ int count = 0; struct mem_item *item, *next; struct mem_zone *zone = strm->opaque;
/* show high water mark */
mem_high(strm, prefix);
/* free leftover allocations and item structures, if any */
item = zone->first; while (item != NULL) {
free(item->ptr);
next = item->next;
free(item);
item = next;
count++;
}
/* issue alerts about anything unexpected */ if (count || zone->total)
fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n",
prefix, zone->total, count); if (zone->notlifo)
fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo); if (zone->rogue)
fprintf(stderr, "** %s: %d frees not recognized\n",
prefix, zone->rogue);
/* free the zone and delete from the stream */
free(zone);
strm->opaque = Z_NULL;
strm->zalloc = Z_NULL;
strm->zfree = Z_NULL;
}
/* -- inflate test routines -- */
/* Decode a hexadecimal string, set *len to length, in[] to the bytes. This decodesliberally,inthathexdigitscanbeadjacent,inwhichcasetwoin arowwritesabyte.Ortheycanbedelimitedbyanynon-hexcharacter, wherethedelimitersareignoredexceptwhenasinglehexdigitisfollowed byadelimiter,wherethatsingledigitwritesabyte.Thereturneddatais allocatedandmusteventuallybefreed.NULLisreturnedifoutofmemory.
If the length is not needed, then len can be NULL. */
local unsignedchar *h2b(constchar *hex, unsigned *len)
{ unsignedchar *in, *re; unsigned next, val;
in = malloc((strlen(hex) + 1) >> 1); if (in == NULL) return NULL;
next = 0;
val = 1; do { if (*hex >= '0' && *hex <= '9')
val = (val << 4) + *hex - '0'; elseif (*hex >= 'A' && *hex <= 'F')
val = (val << 4) + *hex - 'A' + 10; elseif (*hex >= 'a' && *hex <= 'f')
val = (val << 4) + *hex - 'a' + 10; elseif (val != 1 && val < 32) /* one digit followed by delimiter */
val += 240; /* make it look like two digits */ if (val > 255) { /* have two digits */
in[next++] = val & 0xff; /* save the decoded byte */
val = 1; /* start over */
}
} while (*hex++); /* go through the loop with the terminating null */ if (len != NULL)
*len = next;
re = realloc(in, next); return re == NULL ? in : re;
}
/* generic inflate() run, where hex is the hexadecimal input data, what is the texttoincludeinanerrormessage,stepishowmuchinputdatatofeed inflate()oneachcall,orzerotofeeditall,winisthewindowbits parametertoinflateInit2(),lenisthesizeoftheoutputbuffer,anderr istheerrorcodeexpectedfromthefirstinflate()call(thesecond inflate()callisexpectedtoreturnZ_STREAM_END).Ifwinis47,then headerinformationiscollectedwithinflateGetHeader().Ifazlibstream islookingforadictionary,thenanemptydictionaryisprovided.
inflate() is run until all of the input data is consumed. */
local void inf(char *hex, char *what, unsigned step, int win, unsigned len, int err)
{ int ret; unsigned have; unsignedchar *in, *out;
z_stream strm, copy;
gz_header head;
/* cover all inflate() header and trailer cases and code after inflate() */
local void cover_wrap(void)
{ int ret;
z_stream strm, copy; unsignedchar dict[257];
ret = inflate(Z_NULL, 0); assert(ret == Z_STREAM_ERROR);
ret = inflateEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
ret = inflateCopy(Z_NULL, Z_NULL); assert(ret == Z_STREAM_ERROR);
fputs("inflate bad parameters\n", stderr);
/* input and output functions for inflateBack() */
local unsigned pull(void *desc, unsignedchar **buf)
{ staticunsignedint next = 0; staticunsignedchar dat[] = {0x63, 0, 2, 0}; struct inflate_state *state;
if (desc == Z_NULL) {
next = 0; return0; /* no input (already provided at next_in) */
}
state = (void *)((z_stream *)desc)->state; if (state != Z_NULL)
state->mode = SYNC; /* force an otherwise impossible situation */ return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
}
local int push(void *desc, unsignedchar *buf, unsigned len)
{
(void)buf;
(void)len; return desc != Z_NULL; /* force error if desc not null */
}
/* cover inflateBack() up to common deflate data cases and after those */
local void cover_back(void)
{ int ret;
z_stream strm; unsignedchar win[32768];
ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
assert(ret == Z_VERSION_ERROR);
ret = inflateBackInit(Z_NULL, 0, win); assert(ret == Z_STREAM_ERROR);
ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
assert(ret == Z_STREAM_ERROR);
ret = inflateBackEnd(Z_NULL); assert(ret == Z_STREAM_ERROR);
fputs("inflateBack bad parameters\n", stderr);
mem_setup(&strm);
ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
strm.avail_in = 2;
strm.next_in = (void *)"\x03";
ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
assert(ret == Z_STREAM_END); /* force output error */
strm.avail_in = 3;
strm.next_in = (void *)"\x63\x00";
ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
assert(ret == Z_BUF_ERROR); /* force mode error by mucking with state */
ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
assert(ret == Z_STREAM_ERROR);
ret = inflateBackEnd(&strm); assert(ret == Z_OK);
mem_done(&strm, "inflateBack bad state");
ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK);
ret = inflateBackEnd(&strm); assert(ret == Z_OK);
fputs("inflateBack built-in memory routines\n", stderr);
}
/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
local inttry(char *hex, char *id, int err)
{ int ret; unsigned len, size; unsignedchar *in, *out, *win; char *prefix;
z_stream strm;
/* convert to hex */
in = h2b(hex, &len);
assert(in != NULL);
/* allocate work areas */
size = len << 3;
out = malloc(size);
assert(out != NULL);
win = malloc(32768);
assert(win != NULL);
prefix = malloc(strlen(id) + 6);
assert(prefix != NULL);
/* first with inflate */
strcpy(prefix, id);
strcat(prefix, "-late");
mem_setup(&strm);
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit2(&strm, err < 0 ? 47 : -15);
assert(ret == Z_OK);
strm.avail_in = len;
strm.next_in = in; do {
strm.avail_out = size;
strm.next_out = out;
ret = inflate(&strm, Z_TREES);
assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR); if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT) break;
} while (strm.avail_in || strm.avail_out == 0); if (err) {
assert(ret == Z_DATA_ERROR);
assert(strcmp(id, strm.msg) == 0);
}
inflateEnd(&strm);
mem_done(&strm, prefix);
/* then with inflateBack */ if (err >= 0) {
strcpy(prefix, id);
strcat(prefix, "-back");
mem_setup(&strm);
ret = inflateBackInit(&strm, 15, win);
assert(ret == Z_OK);
strm.avail_in = len;
strm.next_in = in;
ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
assert(ret != Z_STREAM_ERROR); if (err) {
assert(ret == Z_DATA_ERROR);
assert(strcmp(id, strm.msg) == 0);
}
inflateBackEnd(&strm);
mem_done(&strm, prefix);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.