[PATCH] erofs-utils: lib: fix BFINAL judgment for kite-deflate

Gao Xiang hsiangkao at linux.alibaba.com
Fri Jul 18 20:14:21 AEST 2025


There should be enough space to generate a new DEFLATE block with an
end-of-block symbol, which requires at least 10 bits for BTYPE 01.

Fixes: 861037f4fc15 ("erofs-utils: add a built-in DEFLATE compressor")
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 lib/kite_deflate.c | 134 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 115 insertions(+), 19 deletions(-)

diff --git a/lib/kite_deflate.c b/lib/kite_deflate.c
index 7e92c7ca..e9f7e40e 100644
--- a/lib/kite_deflate.c
+++ b/lib/kite_deflate.c
@@ -1005,6 +1005,8 @@ static void kite_deflate_writestore(struct kite_deflate *s)
 
 static void kite_deflate_endblock(struct kite_deflate *s)
 {
+	u64 b = s->outlen - s->pos_out;
+
 	if (s->encode_mode == 1) {
 		u32 fixedcost = s->costbits;
 		unsigned int storelen, storeblocks, storecost;
@@ -1025,8 +1027,11 @@ static void kite_deflate_endblock(struct kite_deflate *s)
 		}
 	}
 
-	s->lastblock |= (s->costbits + s->bitpos >=
-			(s->outlen - s->pos_out) * 8);
+	if (s->costbits + s->bitpos +
+	    3 + kstaticHuff_litLenLevels[kSymbolEndOfBlock] >= b * 8) {
+		DBG_BUGON(s->costbits + s->bitpos > b * 8);
+		s->lastblock = true;
+	}
 }
 
 static void kite_deflate_startblock(struct kite_deflate *s)
@@ -1256,38 +1261,129 @@ int kite_deflate_destsize(struct kite_deflate *s, const u8 *in, u8 *out,
 #include <fcntl.h>
 #include <sys/mman.h>
 
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+
+static int kite_deflate_decompress_zlib(const u8 *in, size_t inlen,
+					u8 *out, size_t out_capacity)
+{
+	z_stream z;
+	int res;
+
+	memset(&z, 0, sizeof(z));
+	res = inflateInit2(&z, -15);
+	if (res != Z_OK) {
+		DBG_BUGON(1);
+		return -1;
+	}
+	z.next_in = (void *)in;
+	z.avail_in = inlen;
+	z.next_out = (void *)out;
+	z.avail_out = out_capacity;
+	res = inflate(&z, Z_FINISH);
+	if (res != Z_STREAM_END) {
+		DBG_BUGON(1);
+		return -1;
+	}
+	inflateEnd(&z);
+	return out_capacity - z.avail_out;
+}
+
+static void kite_deflate_decompress_test_zlib(const u8 *in, size_t inlen,
+					      u8 *out, size_t out_capacity,
+					      const u8 *expected_out,
+					      size_t expected_outlen)
+{
+	int outlen;
+
+	outlen = kite_deflate_decompress_zlib(in, inlen, out, out_capacity);
+	BUG_ON(outlen != expected_outlen);
+	if (expected_outlen)
+		BUG_ON(memcmp(out, expected_out, expected_outlen));
+}
+#endif
+
+static void kite_deflate_decompress_test(const u8 *in, size_t inlen,
+					 u8 *out, size_t out_capacity,
+					 const u8 *expected_out,
+					 size_t expected_outlen)
+{
+#ifdef HAVE_ZLIB
+	kite_deflate_decompress_test_zlib(in, inlen, out, out_capacity,
+					  expected_out, expected_outlen);
+#endif
+}
+
+static void kite_deflate_test1(void)
+{
+	struct kite_deflate *s;
+	u8 enc[3], vb[10];
+
+	s = kite_deflate_init(1, 0);
+	BUG_ON(!s || IS_ERR(s));
+
+	s->out = enc;
+	s->outlen = sizeof(enc);
+
+	writebits(s, (kFixedHuffman << 1) + 1, 3);
+	writebits(s, kstaticHuff_mainCodes[kSymbolEndOfBlock],
+		  kstaticHuff_litLenLevels[kSymbolEndOfBlock]);
+	flushbits(s);
+
+	kite_deflate_decompress_test(enc, s->pos_out,
+				     vb, sizeof(vb), NULL, 0);
+}
+
 int main(int argc, char *argv[])
 {
-	int fd;
-	u64 filelength;
-	u8 out[1048576], *buf;
-	int dstsize = 4096;
-	unsigned int srcsize, outsize;
+	unsigned int srcsize, outsize, dstsize, level;
 	struct kite_deflate *s;
+	u8 out[1048576], *buf;
+	u64 filelength;
+	u8 *vbuf;
+	int fd;
 
+	if (argc < 2) {
+		kite_deflate_test1();
+		fprintf(stdout, "PASS\n");
+		return 0;
+	}
+	dstsize = level = 0;
 	fd = open(argv[1], O_RDONLY);
-	if (fd < 0)
-		return -errno;
-	if (argc > 2)
+	BUG_ON(fd < 0);
+	if (argc > 2) {
 		dstsize = atoi(argv[2]);
-	filelength = lseek(fd, 0, SEEK_END);
+		if (argc > 3)
+			level = atoi(argv[3]);
+	}
+	if (!dstsize || dstsize > sizeof(out))
+		dstsize = 4096;
+	if (!level)
+		level = 9;
 
-	s = kite_deflate_init(9, 0);
-	if (IS_ERR(s))
-		return PTR_ERR(s);
+	s = kite_deflate_init(level, 0);
+	BUG_ON(IS_ERR(s));
 
 	filelength = lseek(fd, 0, SEEK_END);
 	buf = mmap(NULL, filelength, PROT_READ, MAP_SHARED, fd, 0);
-	if (buf == MAP_FAILED)
-		return -errno;
+	BUG_ON(buf == MAP_FAILED);
 	close(fd);
 
 	srcsize = filelength;
 	outsize = kite_deflate_destsize(s, buf, out, &srcsize, dstsize);
-	fd = open("out.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
-	write(fd, out, outsize);
-	close(fd);
 	kite_deflate_end(s);
+#ifdef HAVE_ZLIB
+	vbuf = malloc(srcsize);
+	if (!vbuf) {
+		fprintf(stderr, "buffer allocation failed\n");
+	} else {
+		BUG_ON(kite_deflate_decompress_zlib(out, outsize,
+						    vbuf, srcsize) != srcsize);
+		BUG_ON(memcmp(buf, vbuf, srcsize));
+		free(vbuf);
+	}
+#endif
+	BUG_ON(fwrite(out, outsize, 1, stdout) != 1);
 	return 0;
 }
 #endif
-- 
2.43.5



More information about the Linux-erofs mailing list