Back-port 1.6 pngvalid.c

No changes; files are identical

Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
John Bowler 2016-05-29 09:28:39 -07:00
parent a1296131fe
commit 1982dc6c2f

View File

@ -1,7 +1,7 @@
/* pngvalid.c - validate libpng by constructing then reading png files.
*
* Last changed in libpng 1.6.22 [(PENDING RELEASE)]
* Last changed in libpng 1.6.22 [May 26, 2016]
* Copyright (c) 2014-2016 Glenn Randers-Pehrson
* Written by John Cunningham Bowler
*
@ -131,6 +131,17 @@ typedef png_byte *png_const_bytep;
#include <string.h> /* For memcpy, memset */
#include <math.h> /* For floor */
/* Convenience macros. */
#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d))
#define CHUNK_IHDR CHUNK(73,72,68,82)
#define CHUNK_PLTE CHUNK(80,76,84,69)
#define CHUNK_IDAT CHUNK(73,68,65,84)
#define CHUNK_IEND CHUNK(73,69,78,68)
#define CHUNK_cHRM CHUNK(99,72,82,77)
#define CHUNK_gAMA CHUNK(103,65,77,65)
#define CHUNK_sBIT CHUNK(115,66,73,84)
#define CHUNK_sRGB CHUNK(115,82,71,66)
/* Unused formal parameter errors are removed using the following macro which is
* expected to have no bad effects on performance.
*/
@ -711,6 +722,8 @@ typedef struct png_store_file
{
struct png_store_file* next; /* as many as you like... */
char name[FILE_NAME_SIZE];
unsigned int IDAT_bits; /* Number of bits in IDAT size */
png_uint_32 IDAT_size; /* Total size of IDAT data */
png_uint_32 id; /* must be correct (see FILEID) */
png_size_t datacount; /* In this (the last) buffer */
png_store_buffer data; /* Last buffer in file */
@ -766,6 +779,13 @@ typedef struct png_store
char test[128]; /* Name of test */
char error[256];
/* Share fields */
png_uint_32 chunklen; /* Length of chunk+overhead (chunkpos >= 8) */
png_uint_32 chunktype;/* Type of chunk (valid if chunkpos >= 4) */
png_uint_32 chunkpos; /* Position in chunk */
png_uint_32 IDAT_size;/* Accumulated IDAT size in .new */
unsigned int IDAT_bits;/* Cache of the file store value */
/* Read fields */
png_structp pread; /* Used to read a saved file */
png_infop piread;
@ -775,6 +795,9 @@ typedef struct png_store
png_byte* image; /* Buffer for reading interlaced images */
png_size_t cb_image; /* Size of this buffer */
png_size_t cb_row; /* Row size of the image(s) */
uLong IDAT_crc;
png_uint_32 IDAT_len; /* Used when re-chunking IDAT chunks */
png_uint_32 IDAT_pos; /* Used when re-chunking IDAT chunks */
png_uint_32 image_h; /* Number of rows in a single image */
store_pool read_memory_pool;
@ -861,6 +884,11 @@ store_init(png_store* ps)
ps->pwrite = NULL;
ps->piwrite = NULL;
ps->writepos = 0;
ps->chunkpos = 8;
ps->chunktype = 0;
ps->chunklen = 16;
ps->IDAT_size = 0;
ps->IDAT_bits = 0;
ps->new.prev = NULL;
ps->palette = NULL;
ps->npalette = 0;
@ -883,6 +911,11 @@ store_freenew(png_store *ps)
{
store_freebuffer(&ps->new);
ps->writepos = 0;
ps->chunkpos = 8;
ps->chunktype = 0;
ps->chunklen = 16;
ps->IDAT_size = 0;
ps->IDAT_bits = 0;
if (ps->palette != NULL)
{
free(ps->palette);
@ -896,9 +929,6 @@ store_storenew(png_store *ps)
{
png_store_buffer *pb;
if (ps->writepos != STORE_BUFFER_SIZE)
png_error(ps->pwrite, "invalid store call");
pb = voidcast(png_store_buffer*, malloc(sizeof *pb));
if (pb == NULL)
@ -929,21 +959,52 @@ store_freefile(png_store_file **ppf)
}
}
static unsigned int
bits_of(png_uint_32 num)
{
/* Return the number of bits in 'num' */
unsigned int b = 0;
if (num & 0xffff0000U) b += 16U, num >>= 16;
if (num & 0xff00U) b += 8U, num >>= 8;
if (num & 0xf0U) b += 4U, num >>= 4;
if (num & 0xcU) b += 2U, num >>= 2;
if (num & 0x2U) ++b, num >>= 1;
if (num) ++b;
return b; /* 0..32 */
}
/* Main interface to file storeage, after writing a new PNG file (see the API
* below) call store_storefile to store the result with the given name and id.
*/
static void
store_storefile(png_store *ps, png_uint_32 id)
{
png_store_file *pf = voidcast(png_store_file*, malloc(sizeof *pf));
png_store_file *pf;
if (ps->chunkpos != 0U || ps->chunktype != 0U || ps->chunklen != 0U ||
ps->IDAT_size == 0)
png_error(ps->pwrite, "storefile: incomplete write");
pf = voidcast(png_store_file*, malloc(sizeof *pf));
if (pf == NULL)
png_error(ps->pwrite, "storefile: OOM");
safecat(pf->name, sizeof pf->name, 0, ps->wname);
pf->id = id;
pf->data = ps->new;
pf->datacount = ps->writepos;
pf->IDAT_size = ps->IDAT_size;
pf->IDAT_bits = bits_of(ps->IDAT_size);
/* Because the IDAT always has zlib header stuff this must be true: */
if (pf->IDAT_bits == 0U)
png_error(ps->pwrite, "storefile: 0 sized IDAT");
ps->new.prev = NULL;
ps->writepos = 0;
ps->chunkpos = 8;
ps->chunktype = 0;
ps->chunklen = 16;
ps->IDAT_size = 0;
pf->palette = ps->palette;
pf->npalette = ps->npalette;
ps->palette = 0;
@ -1067,7 +1128,7 @@ store_warning(png_structp ppIn, png_const_charp message)
if (!ps->expect_warning)
store_log(ps, pp, message, 0 /* warning */);
else
ps->saw_warning = 1;
ps->saw_warning = 1;
}
/* These somewhat odd functions are used when reading an image to ensure that
@ -1209,32 +1270,119 @@ store_image_check(const png_store* ps, png_const_structp pp, int iImage)
}
#endif /* PNG_READ_SUPPORTED */
static int
valid_chunktype(png_uint_32 chunktype)
{
/* Each byte in the chunk type must be in one of the ranges 65..90, 97..122
* (both inclusive), so:
*/
unsigned int i;
for (i=0; i<4; ++i)
{
unsigned int c = chunktype & 0xffU;
if (!((c >= 65U && c <= 90U) || (c >= 97U && c <= 122U)))
return 0;
chunktype >>= 8;
}
return 1; /* It's valid */
}
static void PNGCBAPI
store_write(png_structp ppIn, png_bytep pb, png_size_t st)
{
png_const_structp pp = ppIn;
png_store *ps = voidcast(png_store*, png_get_io_ptr(pp));
size_t writepos = ps->writepos;
png_uint_32 chunkpos = ps->chunkpos;
png_uint_32 chunktype = ps->chunktype;
png_uint_32 chunklen = ps->chunklen;
if (ps->pwrite != pp)
png_error(pp, "store state damaged");
/* Technically this is legal, but in practice libpng never writes more than
* the maximum chunk size at once so if it happens something weird has
* changed inside libpng (probably).
*/
if (st > 0x7fffffffU)
png_error(pp, "unexpected write size");
/* Now process the bytes to be written. Do this in units of the space in the
* output (write) buffer or, at the start 4 bytes for the chunk type and
* length limited in any case by the amount of data.
*/
while (st > 0)
{
size_t cb;
if (writepos >= STORE_BUFFER_SIZE)
store_storenew(ps), writepos = 0;
if (ps->writepos >= STORE_BUFFER_SIZE)
store_storenew(ps);
if (chunkpos < 4)
{
png_byte b = *pb++;
--st;
chunklen = (chunklen << 8) + b;
ps->new.buffer[writepos++] = b;
++chunkpos;
}
cb = st;
else if (chunkpos < 8)
{
png_byte b = *pb++;
--st;
chunktype = (chunktype << 8) + b;
ps->new.buffer[writepos++] = b;
if (cb > STORE_BUFFER_SIZE - ps->writepos)
cb = STORE_BUFFER_SIZE - ps->writepos;
if (++chunkpos == 8)
{
chunklen &= 0xffffffffU;
if (chunklen > 0x7fffffffU)
png_error(pp, "chunk length too great");
memcpy(ps->new.buffer + ps->writepos, pb, cb);
pb += cb;
st -= cb;
ps->writepos += cb;
}
chunktype &= 0xffffffffU;
if (chunktype == CHUNK_IDAT)
{
if (chunklen > ~ps->IDAT_size)
png_error(pp, "pngvalid internal image too large");
ps->IDAT_size += chunklen;
}
else if (!valid_chunktype(chunktype))
png_error(pp, "invalid chunk type");
chunklen += 12; /* for header and CRC */
}
}
else /* chunkpos >= 8 */
{
png_size_t cb = st;
if (cb > STORE_BUFFER_SIZE - writepos)
cb = STORE_BUFFER_SIZE - writepos;
if (cb > chunklen - chunkpos/* bytes left in chunk*/)
cb = (png_size_t)/*SAFE*/(chunklen - chunkpos);
memcpy(ps->new.buffer + writepos, pb, cb);
chunkpos += (png_uint_32)/*SAFE*/cb;
pb += cb;
writepos += cb;
st -= cb;
if (chunkpos >= chunklen) /* must be equal */
chunkpos = chunktype = chunklen = 0;
}
} /* while (st > 0) */
ps->writepos = writepos;
ps->chunkpos = chunkpos;
ps->chunktype = chunktype;
ps->chunklen = chunklen;
}
static void PNGCBAPI
@ -1254,7 +1402,6 @@ store_read_buffer_size(png_store *ps)
return ps->current->datacount;
}
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* Return total bytes available for read. */
static size_t
store_read_buffer_avail(png_store *ps)
@ -1279,7 +1426,6 @@ store_read_buffer_avail(png_store *ps)
return 0;
}
#endif
static int
store_read_buffer_next(png_store *ps)
@ -1331,6 +1477,242 @@ store_read_imp(png_store *ps, png_bytep pb, png_size_t st)
}
}
static png_size_t
store_read_chunk(png_store *ps, png_bytep pb, const png_size_t max,
const png_size_t min)
{
png_uint_32 chunklen = ps->chunklen;
png_uint_32 chunktype = ps->chunktype;
png_uint_32 chunkpos = ps->chunkpos;
png_size_t st = max;
if (st > 0) do
{
if (chunkpos >= chunklen) /* end of last chunk */
{
png_byte buffer[8];
/* Read the header of the next chunk: */
store_read_imp(ps, buffer, 8U);
chunklen = png_get_uint_32(buffer) + 12U;
chunktype = png_get_uint_32(buffer+4U);
chunkpos = 0U; /* Position read so far */
}
if (chunktype == CHUNK_IDAT)
{
png_uint_32 IDAT_pos = ps->IDAT_pos;
png_uint_32 IDAT_len = ps->IDAT_len;
png_uint_32 IDAT_size = ps->IDAT_size;
/* The IDAT headers are constructed here; skip the input header. */
if (chunkpos < 8U)
chunkpos = 8U;
if (IDAT_pos == IDAT_len)
{
png_byte random;
R8(random);
/* Make a new IDAT chunk, if IDAT_len is 0 this is the first IDAT,
* if IDAT_size is 0 this is the end. At present this is set up
* using a random number so that there is a 25% chance before
* the start of the first IDAT chunk being 0 length.
*/
if (IDAT_len == 0U) /* First IDAT */
{
switch (random & 3U)
{
case 0U: IDAT_len = 12U; break; /* 0 bytes */
case 1U: IDAT_len = 13U; break; /* 1 byte */
default: R32(IDAT_len);
IDAT_len %= IDAT_size;
IDAT_len += 13U; /* 1..IDAT_size bytes */
break;
}
}
else if (IDAT_size == 0U) /* all IDAT data read */
{
/* The last (IDAT) chunk should be positioned at the CRC now: */
if (chunkpos != chunklen-4U)
png_error(ps->pread, "internal: IDAT size mismatch");
/* The only option here is to add a zero length IDAT, this
* happens 25% of the time. Because of the check above
* chunklen-4U-chunkpos must be zero, we just need to skip the
* CRC now.
*/
if ((random & 3U) == 0U)
IDAT_len = 12U; /* Output another 0 length IDAT */
else
{
/* End of IDATs, skip the CRC to make the code above load the
* next chunk header next time round.
*/
png_byte buffer[4];
store_read_imp(ps, buffer, 4U);
chunkpos += 4U;
ps->IDAT_pos = IDAT_pos;
ps->IDAT_len = IDAT_len;
ps->IDAT_size = 0U;
continue; /* Read the next chunk */
}
}
else
{
/* Middle of IDATs, use 'random' to determine the number of bits
* to use in the IDAT length.
*/
R32(IDAT_len);
IDAT_len &= (1U << (1U + random % ps->IDAT_bits)) - 1U;
if (IDAT_len > IDAT_size)
IDAT_len = IDAT_size;
IDAT_len += 12U; /* zero bytes may occur */
}
IDAT_pos = 0U;
ps->IDAT_crc = 0x35af061e; /* Ie: crc32(0UL, "IDAT", 4) */
} /* IDAT_pos == IDAT_len */
if (IDAT_pos < 8U) /* Return the header */ do
{
png_uint_32 b;
unsigned int shift;
if (IDAT_pos < 4U)
b = IDAT_len - 12U;
else
b = CHUNK_IDAT;
shift = 3U & IDAT_pos;
++IDAT_pos;
if (shift < 3U)
b >>= 8U*(3U-shift);
*pb++ = 0xffU & b;
}
while (--st > 0 && IDAT_pos < 8);
else if (IDAT_pos < IDAT_len - 4U) /* I.e not the CRC */
{
if (chunkpos < chunklen-4U)
{
uInt avail = -1;
if (avail > (IDAT_len-4U) - IDAT_pos)
avail = (uInt)/*SAFE*/((IDAT_len-4U) - IDAT_pos);
if (avail > st)
avail = (uInt)/*SAFE*/st;
if (avail > (chunklen-4U) - chunkpos)
avail = (uInt)/*SAFE*/((chunklen-4U) - chunkpos);
store_read_imp(ps, pb, avail);
ps->IDAT_crc = crc32(ps->IDAT_crc, pb, avail);
pb += (png_size_t)/*SAFE*/avail;
st -= (png_size_t)/*SAFE*/avail;
chunkpos += (png_uint_32)/*SAFE*/avail;
IDAT_size -= (png_uint_32)/*SAFE*/avail;
IDAT_pos += (png_uint_32)/*SAFE*/avail;
}
else /* skip the input CRC */
{
png_byte buffer[4];
store_read_imp(ps, buffer, 4U);
chunkpos += 4U;
}
}
else /* IDAT crc */ do
{
uLong b = ps->IDAT_crc;
unsigned int shift = (IDAT_len - IDAT_pos); /* 4..1 */
++IDAT_pos;
if (shift > 1U)
b >>= 8U*(shift-1U);
*pb++ = 0xffU & b;
}
while (--st > 0 && IDAT_pos < IDAT_len);
ps->IDAT_pos = IDAT_pos;
ps->IDAT_len = IDAT_len;
ps->IDAT_size = IDAT_size;
}
else /* !IDAT */
{
/* If there is still some pending IDAT data after the IDAT chunks have
* been processed there is a problem:
*/
if (ps->IDAT_len > 0 && ps->IDAT_size > 0)
png_error(ps->pread, "internal: missing IDAT data");
if (chunktype == CHUNK_IEND && ps->IDAT_len == 0U)
png_error(ps->pread, "internal: missing IDAT");
if (chunkpos < 8U) /* Return the header */ do
{
png_uint_32 b;
unsigned int shift;
if (chunkpos < 4U)
b = chunklen - 12U;
else
b = chunktype;
shift = 3U & chunkpos;
++chunkpos;
if (shift < 3U)
b >>= 8U*(3U-shift);
*pb++ = 0xffU & b;
}
while (--st > 0 && chunkpos < 8);
else /* Return chunk bytes, including the CRC */
{
png_size_t avail = st;
if (avail > chunklen - chunkpos)
avail = (png_size_t)/*SAFE*/(chunklen - chunkpos);
store_read_imp(ps, pb, avail);
pb += avail;
st -= avail;
chunkpos += (png_uint_32)/*SAFE*/avail;
/* Check for end of chunk and end-of-file; don't try to read a new
* chunk header at this point unless instructed to do so by 'min'.
*/
if (chunkpos >= chunklen && max-st >= min &&
store_read_buffer_avail(ps) == 0)
break;
}
} /* !IDAT */
}
while (st > 0);
ps->chunklen = chunklen;
ps->chunktype = chunktype;
ps->chunkpos = chunkpos;
return st; /* space left */
}
static void PNGCBAPI
store_read(png_structp ppIn, png_bytep pb, png_size_t st)
{
@ -1340,26 +1722,33 @@ store_read(png_structp ppIn, png_bytep pb, png_size_t st)
if (ps == NULL || ps->pread != pp)
png_error(pp, "bad store read call");
store_read_imp(ps, pb, st);
store_read_chunk(ps, pb, st, st);
}
static void
store_progressive_read(png_store *ps, png_structp pp, png_infop pi)
{
/* Notice that a call to store_read will cause this function to fail because
* readpos will be set.
*/
if (ps->pread != pp || ps->current == NULL || ps->next == NULL)
png_error(pp, "store state damaged (progressive)");
do
/* This is another Horowitz and Hill random noise generator. In this case
* the aim is to stress the progressive reader with truly horrible variable
* buffer sizes in the range 1..500, so a sequence of 9 bit random numbers
* is generated. We could probably just count from 1 to 32767 and get as
* good a result.
*/
while (store_read_buffer_avail(ps) > 0)
{
if (ps->readpos != 0)
png_error(pp, "store_read called during progressive read");
static png_uint_32 noise = 2;
png_size_t cb;
png_byte buffer[512];
png_process_data(pp, pi, ps->next->buffer, store_read_buffer_size(ps));
/* Generate 15 more bits of stuff: */
noise = (noise << 9) | ((noise ^ (noise >> (9-5))) & 0x1ff);
cb = noise & 0x1ff;
cb -= store_read_chunk(ps, buffer, cb, 1);
png_process_data(pp, pi, buffer, cb);
}
while (store_read_buffer_next(ps));
}
#endif /* PNG_READ_SUPPORTED */
@ -1730,6 +2119,11 @@ store_read_reset(png_store *ps)
ps->next = NULL;
ps->readpos = 0;
ps->validated = 0;
ps->chunkpos = 8;
ps->chunktype = 0;
ps->chunklen = 16;
ps->IDAT_size = 0;
}
#ifdef PNG_READ_SUPPORTED
@ -1744,6 +2138,11 @@ store_read_set(png_store *ps, png_uint_32 id)
{
ps->current = pf;
ps->next = NULL;
ps->IDAT_size = pf->IDAT_size;
ps->IDAT_bits = pf->IDAT_bits; /* just a cache */
ps->IDAT_len = 0;
ps->IDAT_pos = 0;
ps->IDAT_crc = 0UL;
store_read_buffer_next(ps);
return;
}
@ -2581,17 +2980,6 @@ modifier_color_encoding_is_set(const png_modifier *pm)
return pm->current_gamma != 0;
}
/* Convenience macros. */
#define CHUNK(a,b,c,d) (((a)<<24)+((b)<<16)+((c)<<8)+(d))
#define CHUNK_IHDR CHUNK(73,72,68,82)
#define CHUNK_PLTE CHUNK(80,76,84,69)
#define CHUNK_IDAT CHUNK(73,68,65,84)
#define CHUNK_IEND CHUNK(73,69,78,68)
#define CHUNK_cHRM CHUNK(99,72,82,77)
#define CHUNK_gAMA CHUNK(103,65,77,65)
#define CHUNK_sBIT CHUNK(115,66,73,84)
#define CHUNK_sRGB CHUNK(115,82,71,66)
/* The guts of modification are performed during a read. */
static void
modifier_crc(png_bytep buffer)
@ -2631,7 +3019,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
{
static png_byte sign[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
case modifier_start:
store_read_imp(&pm->this, pm->buffer, 8); /* size of signature. */
store_read_chunk(&pm->this, pm->buffer, 8, 8); /* signature. */
pm->buffer_count = 8;
pm->buffer_position = 0;
@ -2641,7 +3029,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
break;
case modifier_signature:
store_read_imp(&pm->this, pm->buffer, 13+12); /* size of IHDR */
store_read_chunk(&pm->this, pm->buffer, 13+12, 13+12); /* IHDR */
pm->buffer_count = 13+12;
pm->buffer_position = 0;
@ -2682,7 +3070,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
{
if (cb > st) cb = st;
pm->flush -= cb;
store_read_imp(&pm->this, pb, cb);
store_read_chunk(&pm->this, pb, cb, cb);
pb += cb;
st -= cb;
if (st == 0) return;
@ -2699,7 +3087,7 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
pm->pending_chunk = 0;
}
else
store_read_imp(&pm->this, pm->buffer, 8);
store_read_chunk(&pm->this, pm->buffer, 8, 8);
pm->buffer_count = 8;
pm->buffer_position = 0;
@ -2765,8 +3153,8 @@ modifier_read_imp(png_modifier *pm, png_bytep pb, png_size_t st)
*/
if (len+12 <= sizeof pm->buffer)
{
store_read_imp(&pm->this, pm->buffer+pm->buffer_count,
len+12-pm->buffer_count);
png_size_t s = len+12-pm->buffer_count;
store_read_chunk(&pm->this, pm->buffer+pm->buffer_count, s, s);
pm->buffer_count = len+12;
/* Check for a modification, else leave it be. */