GNU bug report logs - #63831
fix bug with failed inflation of .el.gz files in src/decompress.c

Previous Next

Package: emacs;

Reported by: Amritpal Singh <icy.amrit <at> gmail.com>

Date: Fri, 2 Jun 2023 07:53:01 UTC

Severity: normal

Tags: patch

Merged with 63832, 63848

Done: Eli Zaretskii <eliz <at> gnu.org>

Bug is archived. No further changes may be made.

Full log


View this message in rfc822 format

From: Amritpal Singh <icy.amrit <at> gmail.com>
To: 63831 <at> debbugs.gnu.org
Subject: bug#63831: [PATCH] Elaboration on the bugfix for failed inflation of gz archives
Date: Sat, 3 Jun 2023 08:38:18 +0530
> Now after logging some code in $EMACS_REPO/src/decompress.c, it was
> learned that in the pigz specific case, `inflate()` was returning
> Z_BUF_ERROR(-5) which is an indicator for zstream's either `avail_in`
> or `avail_out` fields are 0.
>
> Observing the code in `$EMACS_REPO/src/decompress.c`
> L154:
>     } while (!stream.avail_out);
> only checks stream.avail_out and not stream.avail_in which also might
> have been set to 0. A special case here can be constructed where
> `avail_in` is 0, and the code keeps looping even though our input
> buffer is empty and thus causing a Z_BUF_ERROR. Placing a simple check
> for it fixes the bug in pigz's gz archives case and does not cause any
> issue with gzip archives.

I'd like to elaborate a bit further on this part mentioned in the bug
report-cum-patch email. The code in question where the bug occurs is
as follows:

> do {
>    stream.avail_in = fread (in, 1, MD5_BLOCKSIZE, source);
>    if (ferror (source)) {
>      inflateEnd (&stream);
>      return -1;
>    }
>    if (stream.avail_in == 0)
>      break;
>    stream.next_in = in;
>
>    do {
>      stream.avail_out = MD5_BLOCKSIZE;
>      stream.next_out = out;
>      res = inflate (&stream, Z_NO_FLUSH);
>
>      if (res != Z_OK && res != Z_STREAM_END)
>    return -1;
>
>      accumulate_and_process_md5 (out, MD5_BLOCKSIZE - stream.avail_out, &ctx);
L154:
>    } while (!stream.avail_out);
L155:
>
>  } while (res != Z_STREAM_END);


From here, it is a bit more clear what the originally mentioned `L154`
was referring to. The archives compressed using pigz set as the systems'
gzip program either via symlink as `gzip` in $PATH or using $GZIP_PROG,
fail to hash in this specific instance which is quite strange,
nonetheless this patch (provided in the original bug report) fixes the
issue of calling inflate() repeatedly (in the inner do-while() loop)
when we do not have any more input to process.

This happens so, as mentioned before, because `infalte()` can set
`stream.avail_in` to 0 which is the available number of bytes to
process. And since we're only checking if stream.avail_out hasn't been
set to 0 in the inner loop, the hashing fails even though our archive is
correctly made and decompresses successfully externally.

ps. The patch is in the original bug report.




This bug report was last modified 1 year and 295 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.