]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
write_add_filter_bzip2: End compression in the freer
authorDag-Erling Smørgrav <des@des.no>
Mon, 8 Sep 2025 19:20:32 +0000 (21:20 +0200)
committerDag-Erling Smørgrav <des@des.no>
Mon, 8 Sep 2025 21:33:32 +0000 (23:33 +0200)
If a fatal error occurs, the closer will not be called, so neither will
BZ2_bzCompressEnd(), and we will leak memory.  Fix this by calling it a
second time from the freer.  This is harmless in the non-error case as
it will see that the compression state has already been cleared and
immediately return BZ_PARAM_ERROR, which we simply ignore.

libarchive/archive_write_add_filter_bzip2.c
libarchive/test/test_write_filter_bzip2.c

index 0726f08936ec1d9180f2a5a604488dafb8bd7629..2434528d5133b6ed33f31fdb0fa3e0760131180c 100644 (file)
@@ -281,6 +281,10 @@ static int
 archive_compressor_bzip2_free(struct archive_write_filter *f)
 {
        struct private_data *data = (struct private_data *)f->data;
+
+       /* May already have been called, but not necessarily. */
+       (void)BZ2_bzCompressEnd(&(data->stream));
+
        free(data->compressed);
        free(data);
        f->data = NULL;
index 20ca0d9a7b224d71c4eeea572e2184fb6f815782..7b2e4f857a75cd20530964b18cded72adddcc1ed 100644 (file)
@@ -267,6 +267,35 @@ DEFINE_TEST(test_write_filter_bzip2)
        assertEqualInt(ARCHIVE_OK, archive_write_close(a));
        assertEqualInt(ARCHIVE_OK, archive_write_free(a));
 
+       /*
+        * Test behavior after a fatal error (triggered by giving
+        * archive_write_open_memory() a very small buffer).
+        */
+       if (!use_prog) {
+               used1 = 0;
+               assert((a = archive_write_new()) != NULL);
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_write_set_format_ustar(a));
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_write_add_filter_bzip2(a));
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_write_open_memory(a, buff, 100, &used1));
+               assert((ae = archive_entry_new()) != NULL);
+               archive_entry_set_filetype(ae, AE_IFREG);
+               archive_entry_set_size(ae, 4000000);
+               archive_entry_copy_pathname(ae, "file");
+               assertEqualIntA(a, ARCHIVE_OK,
+                   archive_write_header(a, ae));
+               for (i = 0; i < 1000000; i++) {
+                       r = archive_write_data(a, &i, 4);
+                       if (r == ARCHIVE_FATAL)
+                               break;
+               }
+               assertEqualIntA(a, ARCHIVE_FATAL, r);
+               archive_entry_free(ae);
+               assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+       }
+
        /*
         * Clean up.
         */