Package: pngcheck
Version: 2.3.0-7
Severity: wishlist
File: /usr/bin/pngcheck
pngcheck does not detect some cases of bad "window bits" size in the png
file. For example,
https://www.gutenberg.org/files/16713/16713-h/images/q169b2.png
(attached below, in case rectified soon)
pnginfo -d q169b2.png
=> libpng error: IDAT: invalid distance too far back
pngcheck q169b2.png
=> succeeds
whereas I hoped pngcheck would fail.
This is the IDAT "window bits" CINFO too small for what the data
actually needs. pngcheck inflates into a big output buffer and zlib by
default makes use of that, thereby tolerating the problem.
It'd be good if pngcheck used a copy of zlib compiled with its
INFLATE_STRICT option, so as to detect the problem.
Dunno if configury for a suitable copy of zlib would be easy or hard.
I tried a byte-by-byte wrapper which gets the same effect with normal
zlib, but is much less efficient of course.
--- pngcheck.c.orig 2007-07-08 16:23:31.000000000 +1000
+++ pngcheck.c 2018-10-23 17:36:13.000000000 +1100
@@ -1011,6 +1011,26 @@
}
+/* strict_inflate() same as inflate() but enforcing window size in the
+ manner of zlib compiled with its INFLATE_STRICT option. Normally
+ inflate() tolerates window size too small if the output buffer is big
+ enough that it contains the needed data. Going byte by byte here ensures
+ the output buffer isn't and thus window size too small is detected.
+ ENHANCE-ME: Better to use the zlib INFLATE_STRICT option.
+ */
+int strict_inflate(z_stream *z, int flush)
+{
+ /* "extra" is the part of avail_out not presented to inflate() */
+ int err;
+ do {
+ uInt extra = (z->avail_out ? z->avail_out - 1 : 0);
+ z->avail_out -= extra;
+ err = inflate(z, flush);
+ z->avail_out += extra;
+ } while (err == Z_OK && z->avail_in > 0 && z->avail_out > 0);
+ return err;
+}
+
int pngcheck(FILE *fp, char *fname, int searching, FILE *fpOut)
{
@@ -1807,7 +1827,7 @@
while (err != Z_STREAM_END && zstrm.avail_in > 0) {
/* know zstrm.avail_out > 0: get some image/filter data */
- err = inflate(&zstrm, Z_SYNC_FLUSH);
+ err = strict_inflate(&zstrm, Z_SYNC_FLUSH);
if (err != Z_OK && err != Z_STREAM_END) {
printf("%s zlib: inflate error = %d (%s)\n",
verbose > 1? "\n " : (verbose == 1? " ":fname), err,