]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/journal/test-compress.c
Merge pull request #16407 from bluca/verity_reuse
[thirdparty/systemd.git] / src / journal / test-compress.c
index ea1ffcc4afdbb2596c0473e4f77b01424329782f..f50fb0acea82dc635bb5759137e9011a7e2efaeb 100644 (file)
@@ -1,22 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd
 
-  Copyright 2014 Ronny Chevalier
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include <sys/stat.h>
 
 #if HAVE_LZ4
 #include <lz4.h>
 #include "alloc-util.h"
 #include "compress.h"
 #include "fd-util.h"
-#include "fileio.h"
+#include "fs-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "path-util.h"
 #include "random-util.h"
-#include "util.h"
+#include "tests.h"
+#include "tmpfile-util.h"
 
 #if HAVE_XZ
 # define XZ_OK 0
@@ -43,6 +29,8 @@
 # define LZ4_OK -EPROTONOSUPPORT
 #endif
 
+#define HUGE_SIZE (4096*1024)
+
 typedef int (compress_blob_t)(const void *src, uint64_t src_size,
                               void *dst, size_t dst_alloc_size, size_t *dst_size);
 typedef int (decompress_blob_t)(const void *src, uint64_t src_size,
@@ -56,20 +44,20 @@ typedef int (decompress_sw_t)(const void *src, uint64_t src_size,
 typedef int (compress_stream_t)(int fdf, int fdt, uint64_t max_bytes);
 typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
 
-#if HAVE_XZ || HAVE_LZ4
-static void test_compress_decompress(int compression,
-                                     compress_blob_t compress,
-                                     decompress_blob_t decompress,
-                                     const char *data,
-                                     size_t data_len,
-                                     bool may_fail) {
+#if HAVE_COMPRESSION
+_unused_ static void test_compress_decompress(const char *compression,
+                                              compress_blob_t compress,
+                                              decompress_blob_t decompress,
+                                              const char *data,
+                                              size_t data_len,
+                                              bool may_fail) {
         char compressed[512];
         size_t csize, usize = 0;
         _cleanup_free_ char *decompressed = NULL;
         int r;
 
         log_info("/* testing %s %s blob compression/decompression */",
-                 object_compressed_to_string(compression), data);
+                 compression, data);
 
         r = compress(data, data_len, compressed, sizeof(compressed), &csize);
         if (r == -ENOBUFS) {
@@ -100,12 +88,12 @@ static void test_compress_decompress(int compression,
         memzero(decompressed, usize);
 }
 
-static void test_decompress_startswith(int compression,
-                                       compress_blob_t compress,
-                                       decompress_sw_t decompress_sw,
-                                       const char *data,
-                                       size_t data_len,
-                                       bool may_fail) {
+_unused_ static void test_decompress_startswith(const char *compression,
+                                                compress_blob_t compress,
+                                                decompress_sw_t decompress_sw,
+                                                const char *data,
+                                                size_t data_len,
+                                                bool may_fail) {
 
         char *compressed;
         _cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL;
@@ -113,7 +101,7 @@ static void test_decompress_startswith(int compression,
         int r;
 
         log_info("/* testing decompress_startswith with %s on %.20s text */",
-                 object_compressed_to_string(compression), data);
+                 compression, data);
 
 #define BUFSIZE_1 512
 #define BUFSIZE_2 20000
@@ -148,15 +136,42 @@ static void test_decompress_startswith(int compression,
         assert_se(r > 0);
 }
 
-static void test_compress_stream(int compression,
-                                 const char* cat,
-                                 compress_stream_t compress,
-                                 decompress_stream_t decompress,
-                                 const char *srcfile) {
+_unused_ static void test_decompress_startswith_short(const char *compression,
+                                                      compress_blob_t compress,
+                                                      decompress_sw_t decompress_sw) {
+
+#define TEXT "HUGE=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+        char buf[1024];
+        size_t i, csize;
+        int r;
+
+        log_info("/* %s with %s */", __func__, compression);
+
+        r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize);
+        assert_se(r == 0);
+
+        for (i = 1; i < strlen(TEXT); i++) {
+                size_t alloc_size = i;
+                _cleanup_free_ void *buf2 = NULL;
+
+                assert_se(buf2 = malloc(i));
+
+                assert_se(decompress_sw(buf, csize, &buf2, &alloc_size, TEXT, i, TEXT[i]) == 1);
+                assert_se(decompress_sw(buf, csize, &buf2, &alloc_size, TEXT, i, 'y') == 0);
+        }
+}
+
+_unused_ static void test_compress_stream(const char *compression,
+                                          const char *cat,
+                                          compress_stream_t compress,
+                                          decompress_stream_t decompress,
+                                          const char *srcfile) {
 
         _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
-        char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
-             pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
+        _cleanup_(unlink_tempfilep) char
+                pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
+                pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
         int r;
         _cleanup_free_ char *cmd = NULL, *cmd2 = NULL;
         struct stat st = {};
@@ -167,8 +182,7 @@ static void test_compress_stream(int compression,
                 return;
         }
 
-        log_debug("/* testing %s compression */",
-                  object_compressed_to_string(compression));
+        log_debug("/* testing %s compression */", compression);
 
         log_debug("/* create source from %s */", srcfile);
 
@@ -208,29 +222,24 @@ static void test_compress_stream(int compression,
         assert_se(lseek(dst2, 0, SEEK_SET) == 0);
         r = decompress(dst, dst2, st.st_size - 1);
         assert_se(r == -EFBIG);
-
-        assert_se(unlink(pattern) == 0);
-        assert_se(unlink(pattern2) == 0);
 }
 #endif
 
 #if HAVE_LZ4
 static void test_lz4_decompress_partial(void) {
-        char buf[20000];
+        char buf[20000], buf2[100];
         size_t buf_size = sizeof(buf), compressed;
         int r;
         _cleanup_free_ char *huge = NULL;
 
-#define HUGE_SIZE (4096*1024)
-        huge = malloc(HUGE_SIZE);
-        memset(huge, 'x', HUGE_SIZE);
-        memcpy(huge, "HUGE=", 5);
+        log_debug("/* %s */", __func__);
+
+        assert_se(huge = malloc(HUGE_SIZE));
+        memcpy(huge, "HUGE=", STRLEN("HUGE="));
+        memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+        huge[HUGE_SIZE - 1] = '\0';
 
-#if LZ4_VERSION_NUMBER >= 10700
         r = LZ4_compress_default(huge, buf, HUGE_SIZE, buf_size);
-#else
-        r = LZ4_compress_limitedOutput(huge, buf, HUGE_SIZE, buf_size);
-#endif
         assert_se(r >= 0);
         compressed = r;
         log_info("Compressed %i → %zu", HUGE_SIZE, compressed);
@@ -245,20 +254,21 @@ static void test_lz4_decompress_partial(void) {
         assert_se(r >= 0);
         log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE, r);
 
-        /* We expect this to fail, because that's how current lz4 works. If this
-         * call succeeds, then lz4 has been fixed, and we need to change our code.
-         */
-        r = LZ4_decompress_safe_partial(buf, huge,
-                                        compressed,
-                                        12, HUGE_SIZE-1);
-        assert_se(r < 0);
-        log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE-1, r);
+        for (size_t size = 1; size < sizeof(buf2); size++) {
+                /* This failed in older lz4s but works in newer ones. */
+                r = LZ4_decompress_safe_partial(buf, buf2, compressed, size, size);
+                log_info("Decompressed partial %zu/%zu → %i (%s)", size, size, r,
+                                                                   r < 0 ? "bad" : "good");
+                if (r >= 0 && LZ4_versionNumber() >= 10803)
+                        /* lz4 <= 1.8.2 should fail that test, let's only check for newer ones */
+                        assert_se(memcmp(buf2, huge, r) == 0);
+        }
 }
 #endif
 
 int main(int argc, char *argv[]) {
-#if HAVE_XZ || HAVE_LZ4
-        const char text[] =
+#if HAVE_COMPRESSION
+        _unused_ const char text[] =
                 "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
                 "foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
 
@@ -267,63 +277,96 @@ int main(int argc, char *argv[]) {
 
         char data[512] = "random\0";
 
-        char huge[4096*1024];
-        memset(huge, 'x', sizeof(huge));
-        memcpy(huge, "HUGE=", 5);
-        char_array_0(huge);
+        _cleanup_free_ char *huge = NULL;
 
-        log_set_max_level(LOG_DEBUG);
+        assert_se(huge = malloc(HUGE_SIZE));
+        memcpy(huge, "HUGE=", STRLEN("HUGE="));
+        memset(&huge[STRLEN("HUGE=")], 'x', HUGE_SIZE - STRLEN("HUGE=") - 1);
+        huge[HUGE_SIZE - 1] = '\0';
+
+        test_setup_logging(LOG_DEBUG);
 
         random_bytes(data + 7, sizeof(data) - 7);
 
 #if HAVE_XZ
-        test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
                                  text, sizeof(text), false);
-        test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
+        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz,
                                  data, sizeof(data), true);
 
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    text, sizeof(text), false);
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
                                    data, sizeof(data), true);
-        test_decompress_startswith(OBJECT_COMPRESSED_XZ,
+        test_decompress_startswith("XZ",
                                    compress_blob_xz, decompress_startswith_xz,
-                                   huge, sizeof(huge), true);
+                                   huge, HUGE_SIZE, true);
 
-        test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat",
+        test_compress_stream("XZ", "xzcat",
                              compress_stream_xz, decompress_stream_xz, srcfile);
+
+        test_decompress_startswith_short("XZ", compress_blob_xz, decompress_startswith_xz);
+
 #else
         log_info("/* XZ test skipped */");
 #endif
 
 #if HAVE_LZ4
-        test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
                                  text, sizeof(text), false);
-        test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
+        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4,
                                  data, sizeof(data), true);
 
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    text, sizeof(text), false);
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    data, sizeof(data), true);
-        test_decompress_startswith(OBJECT_COMPRESSED_LZ4,
+        test_decompress_startswith("LZ4",
                                    compress_blob_lz4, decompress_startswith_lz4,
-                                   huge, sizeof(huge), true);
+                                   huge, HUGE_SIZE, true);
 
-        test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
+        test_compress_stream("LZ4", "lz4cat",
                              compress_stream_lz4, decompress_stream_lz4, srcfile);
 
         test_lz4_decompress_partial();
+
+        test_decompress_startswith_short("LZ4", compress_blob_lz4, decompress_startswith_lz4);
+
 #else
         log_info("/* LZ4 test skipped */");
 #endif
 
+#if HAVE_ZSTD
+        test_compress_decompress("ZSTD", compress_blob_zstd, decompress_blob_zstd,
+                                 text, sizeof(text), false);
+        test_compress_decompress("ZSTD", compress_blob_zstd, decompress_blob_zstd,
+                                 data, sizeof(data), true);
+
+        test_decompress_startswith("ZSTD",
+                                   compress_blob_zstd, decompress_startswith_zstd,
+                                   text, sizeof(text), false);
+        test_decompress_startswith("ZSTD",
+                                   compress_blob_zstd, decompress_startswith_zstd,
+                                   data, sizeof(data), true);
+        test_decompress_startswith("ZSTD",
+                                   compress_blob_zstd, decompress_startswith_zstd,
+                                   huge, HUGE_SIZE, true);
+
+        test_compress_stream("ZSTD", "zstdcat",
+                             compress_stream_zstd, decompress_stream_zstd, srcfile);
+
+        test_decompress_startswith_short("ZSTD", compress_blob_zstd, decompress_startswith_zstd);
+#else
+        log_info("/* ZSTD test skipped */");
+#endif
+
         return 0;
 #else
+        log_info("/* XZ, LZ4 and ZSTD tests skipped */");
         return EXIT_TEST_SKIP;
 #endif
 }