summaryrefslogtreecommitdiffstats
path: root/src/zstd/contrib/linux-kernel/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/zstd/contrib/linux-kernel/test
parentInitial commit. (diff)
downloadceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz
ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/zstd/contrib/linux-kernel/test')
-rw-r--r--src/zstd/contrib/linux-kernel/test/.gitignore1
-rw-r--r--src/zstd/contrib/linux-kernel/test/DecompressCrash.c85
-rw-r--r--src/zstd/contrib/linux-kernel/test/Makefile43
-rw-r--r--src/zstd/contrib/linux-kernel/test/RoundTripCrash.c162
-rw-r--r--src/zstd/contrib/linux-kernel/test/UserlandTest.cpp565
-rw-r--r--src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp166
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h177
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/compiler.h12
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/errno.h6
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/kernel.h16
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/math64.h11
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/module.h10
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/string.h1
-rw-r--r--src/zstd/contrib/linux-kernel/test/include/linux/types.h2
14 files changed, 1257 insertions, 0 deletions
diff --git a/src/zstd/contrib/linux-kernel/test/.gitignore b/src/zstd/contrib/linux-kernel/test/.gitignore
new file mode 100644
index 000000000..4fc10228d
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/.gitignore
@@ -0,0 +1 @@
+*Test
diff --git a/src/zstd/contrib/linux-kernel/test/DecompressCrash.c b/src/zstd/contrib/linux-kernel/test/DecompressCrash.c
new file mode 100644
index 000000000..2ab7dfe52
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/DecompressCrash.c
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/*
+ This program takes a file in input,
+ performs a zstd round-trip test (compression - decompress)
+ compares the result with original
+ and generates a crash (double free) on corruption detection.
+*/
+
+/*===========================================
+* Dependencies
+*==========================================*/
+#include <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free, exit */
+#include <stdio.h> /* fprintf */
+#include <linux/zstd.h>
+
+/*===========================================
+* Macros
+*==========================================*/
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+
+static ZSTD_DCtx *dctx = NULL;
+void *dws = NULL;
+static void* rBuff = NULL;
+static size_t buffSize = 0;
+
+static void crash(int errorCode){
+ /* abort if AFL/libfuzzer, exit otherwise */
+ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */
+ abort();
+ #else
+ exit(errorCode);
+ #endif
+}
+
+static void decompressCheck(const void* srcBuff, size_t srcBuffSize)
+{
+ size_t const neededBuffSize = 20 * srcBuffSize;
+
+ /* Allocate all buffers and contexts if not already allocated */
+ if (neededBuffSize > buffSize) {
+ free(rBuff);
+ buffSize = 0;
+
+ rBuff = malloc(neededBuffSize);
+ if (!rBuff) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ buffSize = neededBuffSize;
+ }
+ if (!dctx) {
+ size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+ dws = malloc(workspaceSize);
+ if (!dws) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ dctx = ZSTD_initDCtx(dws, workspaceSize);
+ if (!dctx) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ }
+ ZSTD_decompressDCtx(dctx, rBuff, buffSize, srcBuff, srcBuffSize);
+
+#ifndef SKIP_FREE
+ free(dws); dws = NULL; dctx = NULL;
+ free(rBuff); rBuff = NULL;
+ buffSize = 0;
+#endif
+}
+
+int LLVMFuzzerTestOneInput(const unsigned char *srcBuff, size_t srcBuffSize) {
+ decompressCheck(srcBuff, srcBuffSize);
+ return 0;
+}
diff --git a/src/zstd/contrib/linux-kernel/test/Makefile b/src/zstd/contrib/linux-kernel/test/Makefile
new file mode 100644
index 000000000..8411462c9
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/Makefile
@@ -0,0 +1,43 @@
+
+IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include -isystem ../../../lib/common/
+
+SOURCES := $(wildcard ../lib/zstd/*.c)
+OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
+
+ARFLAGS := rcs
+CXXFLAGS += -std=c++11 -g -O3 -Wcast-align
+CFLAGS += -g -O3 -Wframe-larger-than=400 -Wcast-align
+CPPFLAGS += $(IFLAGS)
+
+../lib/zstd/libzstd.a: $(OBJECTS)
+ $(AR) $(ARFLAGS) $@ $^
+
+DecompressCrash: DecompressCrash.o $(OBJECTS) libFuzzer.a
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
+
+RoundTripCrash: RoundTripCrash.o $(OBJECTS) ../lib/xxhash.o libFuzzer.a
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
+
+UserlandTest: UserlandTest.cpp ../lib/zstd/libzstd.a ../lib/xxhash.o
+ $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
+
+XXHashUserlandTest: XXHashUserlandTest.cpp ../lib/xxhash.o ../../../lib/common/xxhash.o
+ $(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
+
+# Install libfuzzer
+libFuzzer.a:
+ @$(RM) -rf Fuzzer
+ @git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer
+ @./Fuzzer/build.sh
+
+# Install googletest
+.PHONY: googletest
+googletest:
+ @$(RM) -rf googletest
+ @git clone https://github.com/google/googletest
+ @mkdir -p googletest/build
+ @cd googletest/build && cmake .. && $(MAKE)
+
+clean:
+ $(RM) -f *.{o,a} ../lib/zstd/*.{o,a} ../lib/*.o
+ $(RM) -f DecompressCrash RoundTripCrash UserlandTest XXHashUserlandTest
diff --git a/src/zstd/contrib/linux-kernel/test/RoundTripCrash.c b/src/zstd/contrib/linux-kernel/test/RoundTripCrash.c
new file mode 100644
index 000000000..4f968023d
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/RoundTripCrash.c
@@ -0,0 +1,162 @@
+/**
+ * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ */
+
+/*
+ This program takes a file in input,
+ performs a zstd round-trip test (compression - decompress)
+ compares the result with original
+ and generates a crash (double free) on corruption detection.
+*/
+
+/*===========================================
+* Dependencies
+*==========================================*/
+#include <stddef.h> /* size_t */
+#include <stdlib.h> /* malloc, free, exit */
+#include <stdio.h> /* fprintf */
+#include <linux/xxhash.h>
+#include <linux/zstd.h>
+
+/*===========================================
+* Macros
+*==========================================*/
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+
+static const int kMaxClevel = 22;
+
+static ZSTD_CCtx *cctx = NULL;
+void *cws = NULL;
+static ZSTD_DCtx *dctx = NULL;
+void *dws = NULL;
+static void* cBuff = NULL;
+static void* rBuff = NULL;
+static size_t buffSize = 0;
+
+
+/** roundTripTest() :
+* Compresses `srcBuff` into `compressedBuff`,
+* then decompresses `compressedBuff` into `resultBuff`.
+* Compression level used is derived from first content byte.
+* @return : result of decompression, which should be == `srcSize`
+* or an error code if either compression or decompression fails.
+* Note : `compressedBuffCapacity` should be `>= ZSTD_compressBound(srcSize)`
+* for compression to be guaranteed to work */
+static size_t roundTripTest(void* resultBuff, size_t resultBuffCapacity,
+ void* compressedBuff, size_t compressedBuffCapacity,
+ const void* srcBuff, size_t srcBuffSize)
+{
+ size_t const hashLength = MIN(128, srcBuffSize);
+ unsigned const h32 = xxh32(srcBuff, hashLength, 0);
+ int const cLevel = h32 % kMaxClevel;
+ ZSTD_parameters const params = ZSTD_getParams(cLevel, srcBuffSize, 0);
+ size_t const cSize = ZSTD_compressCCtx(cctx, compressedBuff, compressedBuffCapacity, srcBuff, srcBuffSize, params);
+ if (ZSTD_isError(cSize)) {
+ fprintf(stderr, "Compression error : %u \n", ZSTD_getErrorCode(cSize));
+ return cSize;
+ }
+ return ZSTD_decompressDCtx(dctx, resultBuff, resultBuffCapacity, compressedBuff, cSize);
+}
+
+
+static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize)
+{
+ const char* ip1 = (const char*)buff1;
+ const char* ip2 = (const char*)buff2;
+ size_t pos;
+
+ for (pos=0; pos<buffSize; pos++)
+ if (ip1[pos]!=ip2[pos])
+ break;
+
+ return pos;
+}
+
+static void crash(int errorCode){
+ /* abort if AFL/libfuzzer, exit otherwise */
+ #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* could also use __AFL_COMPILER */
+ abort();
+ #else
+ exit(errorCode);
+ #endif
+}
+
+static void roundTripCheck(const void* srcBuff, size_t srcBuffSize)
+{
+ size_t const neededBuffSize = ZSTD_compressBound(srcBuffSize);
+
+ /* Allocate all buffers and contexts if not already allocated */
+ if (neededBuffSize > buffSize) {
+ free(cBuff);
+ free(rBuff);
+ buffSize = 0;
+
+ cBuff = malloc(neededBuffSize);
+ rBuff = malloc(neededBuffSize);
+ if (!cBuff || !rBuff) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ buffSize = neededBuffSize;
+ }
+ if (!cctx) {
+ ZSTD_compressionParameters const params = ZSTD_getCParams(kMaxClevel, 0, 0);
+ size_t const workspaceSize = ZSTD_CCtxWorkspaceBound(params);
+ cws = malloc(workspaceSize);
+ if (!cws) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ cctx = ZSTD_initCCtx(cws, workspaceSize);
+ if (!cctx) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ }
+ if (!dctx) {
+ size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+ dws = malloc(workspaceSize);
+ if (!dws) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ dctx = ZSTD_initDCtx(dws, workspaceSize);
+ if (!dctx) {
+ fprintf(stderr, "not enough memory ! \n");
+ crash(1);
+ }
+ }
+
+ { size_t const result = roundTripTest(rBuff, buffSize, cBuff, buffSize, srcBuff, srcBuffSize);
+ if (ZSTD_isError(result)) {
+ fprintf(stderr, "roundTripTest error : %u \n", ZSTD_getErrorCode(result));
+ crash(1);
+ }
+ if (result != srcBuffSize) {
+ fprintf(stderr, "Incorrect regenerated size : %u != %u\n", (unsigned)result, (unsigned)srcBuffSize);
+ crash(1);
+ }
+ if (checkBuffers(srcBuff, rBuff, srcBuffSize) != srcBuffSize) {
+ fprintf(stderr, "Silent decoding corruption !!!");
+ crash(1);
+ }
+ }
+
+#ifndef SKIP_FREE
+ free(cws); cws = NULL; cctx = NULL;
+ free(dws); dws = NULL; dctx = NULL;
+ free(cBuff); cBuff = NULL;
+ free(rBuff); rBuff = NULL;
+ buffSize = 0;
+#endif
+}
+
+int LLVMFuzzerTestOneInput(const unsigned char *srcBuff, size_t srcBuffSize) {
+ roundTripCheck(srcBuff, srcBuffSize);
+ return 0;
+}
diff --git a/src/zstd/contrib/linux-kernel/test/UserlandTest.cpp b/src/zstd/contrib/linux-kernel/test/UserlandTest.cpp
new file mode 100644
index 000000000..03058382f
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/UserlandTest.cpp
@@ -0,0 +1,565 @@
+extern "C" {
+#include <linux/zstd.h>
+}
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+#include <iostream>
+
+using namespace std;
+
+namespace {
+struct WorkspaceDeleter {
+ void *memory;
+
+ template <typename T> void operator()(T const *) { free(memory); }
+};
+
+std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
+createCCtx(ZSTD_compressionParameters cParams) {
+ size_t const workspaceSize = ZSTD_CCtxWorkspaceBound(cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter> cctx{
+ ZSTD_initCCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
+ if (!cctx) {
+ throw std::runtime_error{"Bad cctx"};
+ }
+ return cctx;
+}
+
+std::unique_ptr<ZSTD_CCtx, WorkspaceDeleter>
+createCCtx(int level, unsigned long long estimatedSrcSize = 0,
+ size_t dictSize = 0) {
+ auto const cParams = ZSTD_getCParams(level, estimatedSrcSize, dictSize);
+ return createCCtx(cParams);
+}
+
+std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter>
+createDCtx() {
+ size_t const workspaceSize = ZSTD_DCtxWorkspaceBound();
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_DCtx, WorkspaceDeleter> dctx{
+ ZSTD_initDCtx(workspace, workspaceSize), WorkspaceDeleter{workspace}};
+ if (!dctx) {
+ throw std::runtime_error{"Bad dctx"};
+ }
+ return dctx;
+}
+
+std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
+createCDict(std::string const& dict, ZSTD_parameters params) {
+ size_t const workspaceSize = ZSTD_CDictWorkspaceBound(params.cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CDict, WorkspaceDeleter> cdict{
+ ZSTD_initCDict(dict.data(), dict.size(), params, workspace,
+ workspaceSize),
+ WorkspaceDeleter{workspace}};
+ if (!cdict) {
+ throw std::runtime_error{"Bad cdict"};
+ }
+ return cdict;
+}
+
+std::unique_ptr<ZSTD_CDict, WorkspaceDeleter>
+createCDict(std::string const& dict, int level) {
+ auto const params = ZSTD_getParams(level, 0, dict.size());
+ return createCDict(dict, params);
+}
+
+std::unique_ptr<ZSTD_DDict, WorkspaceDeleter>
+createDDict(std::string const& dict) {
+ size_t const workspaceSize = ZSTD_DDictWorkspaceBound();
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_DDict, WorkspaceDeleter> ddict{
+ ZSTD_initDDict(dict.data(), dict.size(), workspace, workspaceSize),
+ WorkspaceDeleter{workspace}};
+ if (!ddict) {
+ throw std::runtime_error{"Bad ddict"};
+ }
+ return ddict;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(ZSTD_parameters params, unsigned long long pledgedSrcSize = 0) {
+ size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(params.cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
+ ZSTD_initCStream(params, pledgedSrcSize, workspace, workspaceSize)};
+ if (!zcs) {
+ throw std::runtime_error{"bad cstream"};
+ }
+ return zcs;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(ZSTD_compressionParameters cParams, ZSTD_CDict const &cdict,
+ unsigned long long pledgedSrcSize = 0) {
+ size_t const workspaceSize = ZSTD_CStreamWorkspaceBound(cParams);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_CStream, WorkspaceDeleter> zcs{
+ ZSTD_initCStream_usingCDict(&cdict, pledgedSrcSize, workspace,
+ workspaceSize)};
+ if (!zcs) {
+ throw std::runtime_error{"bad cstream"};
+ }
+ return zcs;
+}
+
+std::unique_ptr<ZSTD_CStream, WorkspaceDeleter>
+createCStream(int level, unsigned long long pledgedSrcSize = 0) {
+ auto const params = ZSTD_getParams(level, pledgedSrcSize, 0);
+ return createCStream(params, pledgedSrcSize);
+}
+
+std::unique_ptr<ZSTD_DStream, WorkspaceDeleter>
+createDStream(size_t maxWindowSize = (1ULL << ZSTD_WINDOWLOG_MAX),
+ ZSTD_DDict const *ddict = nullptr) {
+ size_t const workspaceSize = ZSTD_DStreamWorkspaceBound(maxWindowSize);
+ void *workspace = malloc(workspaceSize);
+ std::unique_ptr<ZSTD_DStream, WorkspaceDeleter> zds{
+ ddict == nullptr
+ ? ZSTD_initDStream(maxWindowSize, workspace, workspaceSize)
+ : ZSTD_initDStream_usingDDict(maxWindowSize, ddict, workspace,
+ workspaceSize)};
+ if (!zds) {
+ throw std::runtime_error{"bad dstream"};
+ }
+ return zds;
+}
+
+std::string compress(ZSTD_CCtx &cctx, std::string const &data,
+ ZSTD_parameters params, std::string const &dict = "") {
+ std::string compressed;
+ compressed.resize(ZSTD_compressBound(data.size()));
+ size_t const rc =
+ dict.empty()
+ ? ZSTD_compressCCtx(&cctx, &compressed[0], compressed.size(),
+ data.data(), data.size(), params)
+ : ZSTD_compress_usingDict(&cctx, &compressed[0], compressed.size(),
+ data.data(), data.size(), dict.data(),
+ dict.size(), params);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compression error"};
+ }
+ compressed.resize(rc);
+ return compressed;
+}
+
+std::string compress(ZSTD_CCtx& cctx, std::string const& data, int level, std::string const& dict = "") {
+ auto const params = ZSTD_getParams(level, 0, dict.size());
+ return compress(cctx, data, params, dict);
+}
+
+std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, std::string const& dict = "") {
+ std::string decompressed;
+ decompressed.resize(decompressedSize);
+ size_t const rc =
+ dict.empty()
+ ? ZSTD_decompressDCtx(&dctx, &decompressed[0], decompressed.size(),
+ compressed.data(), compressed.size())
+ : ZSTD_decompress_usingDict(
+ &dctx, &decompressed[0], decompressed.size(), compressed.data(),
+ compressed.size(), dict.data(), dict.size());
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompression error"};
+ }
+ decompressed.resize(rc);
+ return decompressed;
+}
+
+std::string compress(ZSTD_CCtx& cctx, std::string const& data, ZSTD_CDict& cdict) {
+ std::string compressed;
+ compressed.resize(ZSTD_compressBound(data.size()));
+ size_t const rc =
+ ZSTD_compress_usingCDict(&cctx, &compressed[0], compressed.size(),
+ data.data(), data.size(), &cdict);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compression error"};
+ }
+ compressed.resize(rc);
+ return compressed;
+}
+
+std::string decompress(ZSTD_DCtx& dctx, std::string const& compressed, size_t decompressedSize, ZSTD_DDict& ddict) {
+ std::string decompressed;
+ decompressed.resize(decompressedSize);
+ size_t const rc =
+ ZSTD_decompress_usingDDict(&dctx, &decompressed[0], decompressed.size(),
+ compressed.data(), compressed.size(), &ddict);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompression error"};
+ }
+ decompressed.resize(rc);
+ return decompressed;
+}
+
+std::string compress(ZSTD_CStream& zcs, std::string const& data) {
+ std::string compressed;
+ compressed.resize(ZSTD_compressBound(data.size()));
+ ZSTD_inBuffer in = {data.data(), data.size(), 0};
+ ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_compressStream(&zcs, &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compress stream failed"};
+ }
+ }
+ size_t const rc = ZSTD_endStream(&zcs, &out);
+ if (rc != 0) {
+ throw std::runtime_error{"compress end failed"};
+ }
+ compressed.resize(out.pos);
+ return compressed;
+}
+
+std::string decompress(ZSTD_DStream &zds, std::string const &compressed,
+ size_t decompressedSize) {
+ std::string decompressed;
+ decompressed.resize(decompressedSize);
+ ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
+ ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_decompressStream(&zds, &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompress stream failed"};
+ }
+ }
+ decompressed.resize(out.pos);
+ return decompressed;
+}
+
+std::string makeData(size_t size) {
+ std::string result;
+ result.reserve(size + 20);
+ while (result.size() < size) {
+ result += "Hello world";
+ }
+ return result;
+}
+
+std::string const kData = "Hello world";
+std::string const kPlainDict = makeData(10000);
+std::string const kZstdDict{
+ "\x37\xA4\x30\xEC\x99\x69\x58\x1C\x21\x10\xD8\x4A\x84\x01\xCC\xF3"
+ "\x3C\xCF\x9B\x25\xBB\xC9\x6E\xB2\x9B\xEC\x26\xAD\xCF\xDF\x4E\xCD"
+ "\xF3\x2C\x3A\x21\x84\x10\x42\x08\x21\x01\x33\xF1\x78\x3C\x1E\x8F"
+ "\xC7\xE3\xF1\x78\x3C\xCF\xF3\xBC\xF7\xD4\x42\x41\x41\x41\x41\x41"
+ "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41"
+ "\x41\x41\x41\x41\xA1\x50\x28\x14\x0A\x85\x42\xA1\x50\x28\x14\x0A"
+ "\x85\xA2\x28\x8A\xA2\x28\x4A\x29\x7D\x74\xE1\xE1\xE1\xE1\xE1\xE1"
+ "\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xE1\xF1\x78\x3C"
+ "\x1E\x8F\xC7\xE3\xF1\x78\x9E\xE7\x79\xEF\x01\x01\x00\x00\x00\x04"
+ "\x00\x00\x00\x08\x00\x00\x00"
+ "0123456789",
+ 161};
+}
+
+TEST(Block, CCtx) {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, NoContentSize) {
+ auto cctx = createCCtx(1);
+ auto const c = compress(*cctx, kData, 1);
+ auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
+ EXPECT_EQ(ZSTD_CONTENTSIZE_UNKNOWN, size);
+}
+
+TEST(Block, ContentSize) {
+ auto cctx = createCCtx(1);
+ auto params = ZSTD_getParams(1, 0, 0);
+ params.fParams.contentSizeFlag = 1;
+ auto const c = compress(*cctx, kData, params);
+ auto const size = ZSTD_findDecompressedSize(c.data(), c.size());
+ EXPECT_EQ(kData.size(), size);
+}
+
+TEST(Block, CCtxLevelIncrease) {
+ std::string c;
+ auto cctx = createCCtx(22);
+ auto dctx = createDCtx();
+ for (int level = 1; level <= 22; ++level) {
+ auto compressed = compress(*cctx, kData, level);
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Block, PlainDict) {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1, kPlainDict);
+ auto dctx = createDCtx();
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), kPlainDict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, ZstdDict) {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1, kZstdDict);
+ auto dctx = createDCtx();
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), kZstdDict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, PreprocessedPlainDict) {
+ auto cctx = createCCtx(1);
+ auto const cdict = createCDict(kPlainDict, 1);
+ auto const compressed = compress(*cctx, kData, *cdict);
+ auto dctx = createDCtx();
+ auto const ddict = createDDict(kPlainDict);
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), *ddict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, PreprocessedZstdDict) {
+ auto cctx = createCCtx(1);
+ auto const cdict = createCDict(kZstdDict, 1);
+ auto const compressed = compress(*cctx, kData, *cdict);
+ auto dctx = createDCtx();
+ auto const ddict = createDDict(kZstdDict);
+ EXPECT_ANY_THROW(decompress(*dctx, compressed, kData.size()));
+ auto const decompressed =
+ decompress(*dctx, compressed, kData.size(), *ddict);
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Block, ReinitializeCCtx) {
+ auto cctx = createCCtx(1);
+ {
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+ // Create the cctx with the same memory
+ auto d = cctx.get_deleter();
+ auto raw = cctx.release();
+ auto params = ZSTD_getParams(1, 0, 0);
+ cctx.reset(
+ ZSTD_initCCtx(d.memory, ZSTD_CCtxWorkspaceBound(params.cParams)));
+ // Repeat
+ {
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Block, ReinitializeDCtx) {
+ auto dctx = createDCtx();
+ {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1);
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+ // Create the cctx with the same memory
+ auto d = dctx.get_deleter();
+ auto raw = dctx.release();
+ dctx.reset(ZSTD_initDCtx(d.memory, ZSTD_DCtxWorkspaceBound()));
+ // Repeat
+ {
+ auto cctx = createCCtx(1);
+ auto const compressed = compress(*cctx, kData, 1);
+ auto dctx = createDCtx();
+ auto const decompressed = decompress(*dctx, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Stream, Basic) {
+ auto zcs = createCStream(1);
+ auto const compressed = compress(*zcs, kData);
+ auto zds = createDStream();
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, PlainDict) {
+ auto params = ZSTD_getParams(1, kData.size(), kPlainDict.size());
+ params.cParams.windowLog = 17;
+ auto cdict = createCDict(kPlainDict, params);
+ auto zcs = createCStream(params.cParams, *cdict, kData.size());
+ auto const compressed = compress(*zcs, kData);
+ auto const contentSize =
+ ZSTD_findDecompressedSize(compressed.data(), compressed.size());
+ EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
+ auto ddict = createDDict(kPlainDict);
+ auto zds = createDStream(1 << 17, ddict.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, ZstdDict) {
+ auto params = ZSTD_getParams(1, 0, 0);
+ params.cParams.windowLog = 17;
+ auto cdict = createCDict(kZstdDict, 1);
+ auto zcs = createCStream(params.cParams, *cdict);
+ auto const compressed = compress(*zcs, kData);
+ EXPECT_ANY_THROW(decompress(*createDStream(), compressed, kData.size()));
+ auto ddict = createDDict(kZstdDict);
+ auto zds = createDStream(1 << 17, ddict.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, ResetCStream) {
+ auto zcs = createCStream(1);
+ auto zds = createDStream();
+ {
+ auto const compressed = compress(*zcs, kData);
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+ {
+ ZSTD_resetCStream(zcs.get(), 0);
+ auto const compressed = compress(*zcs, kData);
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+TEST(Stream, ResetDStream) {
+ auto zcs = createCStream(1);
+ auto zds = createDStream();
+ auto const compressed = compress(*zcs, kData);
+ EXPECT_ANY_THROW(decompress(*zds, kData, kData.size()));
+ EXPECT_ANY_THROW(decompress(*zds, compressed, kData.size()));
+ ZSTD_resetDStream(zds.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, Flush) {
+ auto zcs = createCStream(1);
+ auto zds = createDStream();
+ std::string compressed;
+ {
+ compressed.resize(ZSTD_compressBound(kData.size()));
+ ZSTD_inBuffer in = {kData.data(), kData.size(), 0};
+ ZSTD_outBuffer out = {&compressed[0], compressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_compressStream(zcs.get(), &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"compress stream failed"};
+ }
+ }
+ EXPECT_EQ(0, out.pos);
+ size_t const rc = ZSTD_flushStream(zcs.get(), &out);
+ if (rc != 0) {
+ throw std::runtime_error{"compress end failed"};
+ }
+ compressed.resize(out.pos);
+ EXPECT_LT(0, out.pos);
+ }
+ std::string decompressed;
+ {
+ decompressed.resize(kData.size());
+ ZSTD_inBuffer in = {compressed.data(), compressed.size(), 0};
+ ZSTD_outBuffer out = {&decompressed[0], decompressed.size(), 0};
+ while (in.pos != in.size) {
+ size_t const rc = ZSTD_decompressStream(zds.get(), &out, &in);
+ if (ZSTD_isError(rc)) {
+ throw std::runtime_error{"decompress stream failed"};
+ }
+ }
+ }
+ EXPECT_EQ(kData, decompressed);
+}
+
+TEST(Stream, DStreamLevelIncrease) {
+ auto zds = createDStream();
+ for (int level = 1; level <= 22; ++level) {
+ auto zcs = createCStream(level);
+ auto compressed = compress(*zcs, kData);
+ ZSTD_resetDStream(zds.get());
+ auto const decompressed = decompress(*zds, compressed, kData.size());
+ EXPECT_EQ(kData, decompressed);
+ }
+}
+
+#define TEST_SYMBOL(symbol) \
+ do { \
+ extern void *__##symbol; \
+ EXPECT_NE((void *)0, __##symbol); \
+ } while (0)
+
+TEST(API, Symbols) {
+ TEST_SYMBOL(ZSTD_CCtxWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initCCtx);
+ TEST_SYMBOL(ZSTD_compressCCtx);
+ TEST_SYMBOL(ZSTD_compress_usingDict);
+ TEST_SYMBOL(ZSTD_DCtxWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initDCtx);
+ TEST_SYMBOL(ZSTD_decompressDCtx);
+ TEST_SYMBOL(ZSTD_decompress_usingDict);
+
+ TEST_SYMBOL(ZSTD_CDictWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initCDict);
+ TEST_SYMBOL(ZSTD_compress_usingCDict);
+ TEST_SYMBOL(ZSTD_DDictWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initDDict);
+ TEST_SYMBOL(ZSTD_decompress_usingDDict);
+
+ TEST_SYMBOL(ZSTD_CStreamWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initCStream);
+ TEST_SYMBOL(ZSTD_initCStream_usingCDict);
+ TEST_SYMBOL(ZSTD_resetCStream);
+ TEST_SYMBOL(ZSTD_compressStream);
+ TEST_SYMBOL(ZSTD_flushStream);
+ TEST_SYMBOL(ZSTD_endStream);
+ TEST_SYMBOL(ZSTD_CStreamInSize);
+ TEST_SYMBOL(ZSTD_CStreamOutSize);
+ TEST_SYMBOL(ZSTD_DStreamWorkspaceBound);
+ TEST_SYMBOL(ZSTD_initDStream);
+ TEST_SYMBOL(ZSTD_initDStream_usingDDict);
+ TEST_SYMBOL(ZSTD_resetDStream);
+ TEST_SYMBOL(ZSTD_decompressStream);
+ TEST_SYMBOL(ZSTD_DStreamInSize);
+ TEST_SYMBOL(ZSTD_DStreamOutSize);
+
+ TEST_SYMBOL(ZSTD_findFrameCompressedSize);
+ TEST_SYMBOL(ZSTD_getFrameContentSize);
+ TEST_SYMBOL(ZSTD_findDecompressedSize);
+
+ TEST_SYMBOL(ZSTD_getCParams);
+ TEST_SYMBOL(ZSTD_getParams);
+ TEST_SYMBOL(ZSTD_checkCParams);
+ TEST_SYMBOL(ZSTD_adjustCParams);
+
+ TEST_SYMBOL(ZSTD_isFrame);
+ TEST_SYMBOL(ZSTD_getDictID_fromDict);
+ TEST_SYMBOL(ZSTD_getDictID_fromDDict);
+ TEST_SYMBOL(ZSTD_getDictID_fromFrame);
+
+ TEST_SYMBOL(ZSTD_compressBegin);
+ TEST_SYMBOL(ZSTD_compressBegin_usingDict);
+ TEST_SYMBOL(ZSTD_compressBegin_advanced);
+ TEST_SYMBOL(ZSTD_copyCCtx);
+ TEST_SYMBOL(ZSTD_compressBegin_usingCDict);
+ TEST_SYMBOL(ZSTD_compressContinue);
+ TEST_SYMBOL(ZSTD_compressEnd);
+ TEST_SYMBOL(ZSTD_getFrameParams);
+ TEST_SYMBOL(ZSTD_decompressBegin);
+ TEST_SYMBOL(ZSTD_decompressBegin_usingDict);
+ TEST_SYMBOL(ZSTD_copyDCtx);
+ TEST_SYMBOL(ZSTD_nextSrcSizeToDecompress);
+ TEST_SYMBOL(ZSTD_decompressContinue);
+ TEST_SYMBOL(ZSTD_nextInputType);
+
+ TEST_SYMBOL(ZSTD_getBlockSizeMax);
+ TEST_SYMBOL(ZSTD_compressBlock);
+ TEST_SYMBOL(ZSTD_decompressBlock);
+ TEST_SYMBOL(ZSTD_insertBlock);
+}
diff --git a/src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp b/src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp
new file mode 100644
index 000000000..f50401a2e
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/XXHashUserlandTest.cpp
@@ -0,0 +1,166 @@
+extern "C" {
+#include <linux/errno.h>
+#include <linux/xxhash.h>
+}
+#include <gtest/gtest.h>
+#include <array>
+#include <iostream>
+#include <memory>
+#include <string>
+#define XXH_STATIC_LINKING_ONLY
+#include <xxhash.h>
+
+using namespace std;
+
+namespace {
+const std::array<std::string, 11> kTestInputs = {
+ "",
+ "0",
+ "01234",
+ "0123456789abcde",
+ "0123456789abcdef",
+ "0123456789abcdef0",
+ "0123456789abcdef0123",
+ "0123456789abcdef0123456789abcde",
+ "0123456789abcdef0123456789abcdef",
+ "0123456789abcdef0123456789abcdef0",
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+};
+
+bool testXXH32(const void *input, const size_t length, uint32_t seed) {
+ return XXH32(input, length, seed) == xxh32(input, length, seed);
+}
+
+bool testXXH64(const void *input, const size_t length, uint32_t seed) {
+ return XXH64(input, length, seed) == xxh64(input, length, seed);
+}
+
+class XXH32State {
+ struct xxh32_state kernelState;
+ XXH32_state_t state;
+
+public:
+ explicit XXH32State(const uint32_t seed) { reset(seed); }
+ XXH32State(XXH32State const& other) noexcept {
+ xxh32_copy_state(&kernelState, &other.kernelState);
+ XXH32_copyState(&state, &other.state);
+ }
+ XXH32State& operator=(XXH32State const& other) noexcept {
+ xxh32_copy_state(&kernelState, &other.kernelState);
+ XXH32_copyState(&state, &other.state);
+ return *this;
+ }
+
+ void reset(const uint32_t seed) {
+ xxh32_reset(&kernelState, seed);
+ EXPECT_EQ(0, XXH32_reset(&state, seed));
+ }
+
+ void update(const void *input, const size_t length) {
+ EXPECT_EQ(0, xxh32_update(&kernelState, input, length));
+ EXPECT_EQ(0, (int)XXH32_update(&state, input, length));
+ }
+
+ bool testDigest() const {
+ return xxh32_digest(&kernelState) == XXH32_digest(&state);
+ }
+};
+
+class XXH64State {
+ struct xxh64_state kernelState;
+ XXH64_state_t state;
+
+public:
+ explicit XXH64State(const uint64_t seed) { reset(seed); }
+ XXH64State(XXH64State const& other) noexcept {
+ xxh64_copy_state(&kernelState, &other.kernelState);
+ XXH64_copyState(&state, &other.state);
+ }
+ XXH64State& operator=(XXH64State const& other) noexcept {
+ xxh64_copy_state(&kernelState, &other.kernelState);
+ XXH64_copyState(&state, &other.state);
+ return *this;
+ }
+
+ void reset(const uint64_t seed) {
+ xxh64_reset(&kernelState, seed);
+ EXPECT_EQ(0, XXH64_reset(&state, seed));
+ }
+
+ void update(const void *input, const size_t length) {
+ EXPECT_EQ(0, xxh64_update(&kernelState, input, length));
+ EXPECT_EQ(0, (int)XXH64_update(&state, input, length));
+ }
+
+ bool testDigest() const {
+ return xxh64_digest(&kernelState) == XXH64_digest(&state);
+ }
+};
+}
+
+TEST(Simple, Null) {
+ EXPECT_TRUE(testXXH32(NULL, 0, 0));
+ EXPECT_TRUE(testXXH64(NULL, 0, 0));
+}
+
+TEST(Stream, Null) {
+ struct xxh32_state state32;
+ xxh32_reset(&state32, 0);
+ EXPECT_EQ(-EINVAL, xxh32_update(&state32, NULL, 0));
+
+ struct xxh64_state state64;
+ xxh64_reset(&state64, 0);
+ EXPECT_EQ(-EINVAL, xxh64_update(&state64, NULL, 0));
+}
+
+TEST(Simple, TestInputs) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ for (auto const input : kTestInputs) {
+ EXPECT_TRUE(testXXH32(input.data(), input.size(), seed));
+ EXPECT_TRUE(testXXH64(input.data(), input.size(), (uint64_t)seed));
+ }
+ }
+}
+
+TEST(Stream, TestInputs) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ for (auto const input : kTestInputs) {
+ XXH32State s32(seed);
+ XXH64State s64(seed);
+ s32.update(input.data(), input.size());
+ s64.update(input.data(), input.size());
+ EXPECT_TRUE(s32.testDigest());
+ EXPECT_TRUE(s64.testDigest());
+ }
+ }
+}
+
+TEST(Stream, MultipleTestInputs) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ XXH32State s32(seed);
+ XXH64State s64(seed);
+ for (auto const input : kTestInputs) {
+ s32.update(input.data(), input.size());
+ s64.update(input.data(), input.size());
+ }
+ EXPECT_TRUE(s32.testDigest());
+ EXPECT_TRUE(s64.testDigest());
+ }
+}
+
+TEST(Stream, CopyState) {
+ for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
+ XXH32State s32(seed);
+ XXH64State s64(seed);
+ for (auto const input : kTestInputs) {
+ auto t32(s32);
+ t32.update(input.data(), input.size());
+ s32 = t32;
+ auto t64(s64);
+ t64.update(input.data(), input.size());
+ s64 = t64;
+ }
+ EXPECT_TRUE(s32.testDigest());
+ EXPECT_TRUE(s64.testDigest());
+ }
+}
diff --git a/src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h b/src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h
new file mode 100644
index 000000000..4f4828126
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/asm/unaligned.h
@@ -0,0 +1,177 @@
+#ifndef ASM_UNALIGNED_H
+#define ASM_UNALIGNED_H
+
+#include <assert.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#define _LITTLE_ENDIAN 1
+
+static unsigned _isLittleEndian(void)
+{
+ const union { uint32_t u; uint8_t c[4]; } one = { 1 };
+ assert(_LITTLE_ENDIAN == one.c[0]);
+ return _LITTLE_ENDIAN;
+}
+
+static uint16_t _swap16(uint16_t in)
+{
+ return ((in & 0xF) << 8) + ((in & 0xF0) >> 8);
+}
+
+static uint32_t _swap32(uint32_t in)
+{
+ return __builtin_bswap32(in);
+}
+
+static uint64_t _swap64(uint64_t in)
+{
+ return __builtin_bswap64(in);
+}
+
+/* Little endian */
+static uint16_t get_unaligned_le16(const void* memPtr)
+{
+ uint16_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (!_isLittleEndian()) _swap16(val);
+ return val;
+}
+
+static uint32_t get_unaligned_le32(const void* memPtr)
+{
+ uint32_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (!_isLittleEndian()) _swap32(val);
+ return val;
+}
+
+static uint64_t get_unaligned_le64(const void* memPtr)
+{
+ uint64_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (!_isLittleEndian()) _swap64(val);
+ return val;
+}
+
+static void put_unaligned_le16(uint16_t value, void* memPtr)
+{
+ if (!_isLittleEndian()) value = _swap16(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_le32(uint32_t value, void* memPtr)
+{
+ if (!_isLittleEndian()) value = _swap32(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_le64(uint64_t value, void* memPtr)
+{
+ if (!_isLittleEndian()) value = _swap64(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+/* big endian */
+static uint32_t get_unaligned_be32(const void* memPtr)
+{
+ uint32_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (_isLittleEndian()) _swap32(val);
+ return val;
+}
+
+static uint64_t get_unaligned_be64(const void* memPtr)
+{
+ uint64_t val;
+ memcpy(&val, memPtr, sizeof(val));
+ if (_isLittleEndian()) _swap64(val);
+ return val;
+}
+
+static void put_unaligned_be32(uint32_t value, void* memPtr)
+{
+ if (_isLittleEndian()) value = _swap32(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+static void put_unaligned_be64(uint64_t value, void* memPtr)
+{
+ if (_isLittleEndian()) value = _swap64(value);
+ memcpy(memPtr, &value, sizeof(value));
+}
+
+/* generic */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __get_unaligned_be(ptr) ((typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __put_unaligned_le(val, ptr) \
+ ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(uint8_t *)__gu_p = (uint8_t)(val); \
+ break; \
+ case 2: \
+ put_unaligned_le16((uint16_t)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_le32((uint32_t)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_le64((uint64_t)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; \
+ })
+
+#define __put_unaligned_be(val, ptr) \
+ ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(uint8_t *)__gu_p = (uint8_t)(val); \
+ break; \
+ case 2: \
+ put_unaligned_be16((uint16_t)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_be32((uint32_t)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_be64((uint64_t)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; \
+ })
+
+#if _LITTLE_ENDIAN
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#else
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#endif
+
+#endif // ASM_UNALIGNED_H
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/compiler.h b/src/zstd/contrib/linux-kernel/test/include/linux/compiler.h
new file mode 100644
index 000000000..4fb4f42e2
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/compiler.h
@@ -0,0 +1,12 @@
+#ifndef LINUX_COMPILER_H_
+#define LINUX_COMPILER_H_
+
+#ifndef __always_inline
+# define __always_inline inline
+#endif
+
+#ifndef noinline
+# define noinline __attribute__((__noinline__))
+#endif
+
+#endif // LINUX_COMPILER_H_
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/errno.h b/src/zstd/contrib/linux-kernel/test/include/linux/errno.h
new file mode 100644
index 000000000..b9db08524
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/errno.h
@@ -0,0 +1,6 @@
+#ifndef LINUX_ERRNO_H_
+#define LINUX_ERRNO_H_
+
+#define EINVAL 22
+
+#endif // LINUX_ERRNO_H_
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/kernel.h b/src/zstd/contrib/linux-kernel/test/include/linux/kernel.h
new file mode 100644
index 000000000..3ef2f7fe8
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/kernel.h
@@ -0,0 +1,16 @@
+#ifndef LINUX_KERNEL_H_
+#define LINUX_KERNEL_H_
+
+#define ALIGN(x, a) ({ \
+ typeof(x) const __xe = (x); \
+ typeof(a) const __ae = (a); \
+ typeof(a) const __m = __ae - 1; \
+ typeof(x) const __r = __xe & __m; \
+ __xe + (__r ? (__ae - __r) : 0); \
+ })
+
+#define PTR_ALIGN(p, a) (typeof(p))ALIGN((unsigned long long)(p), (a))
+
+#define current Something that doesn't compile :)
+
+#endif // LINUX_KERNEL_H_
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/math64.h b/src/zstd/contrib/linux-kernel/test/include/linux/math64.h
new file mode 100644
index 000000000..3d0ae72d5
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/math64.h
@@ -0,0 +1,11 @@
+#ifndef LINUX_MATH64_H
+#define LINUX_MATH64_H
+
+#include <stdint.h>
+
+static uint64_t div_u64(uint64_t n, uint32_t d)
+{
+ return n / d;
+}
+
+#endif
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/module.h b/src/zstd/contrib/linux-kernel/test/include/linux/module.h
new file mode 100644
index 000000000..ef514c349
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/module.h
@@ -0,0 +1,10 @@
+#ifndef LINUX_MODULE_H_
+#define LINUX_MODULE_H_
+
+#define EXPORT_SYMBOL(symbol) \
+ void* __##symbol = symbol
+#define MODULE_LICENSE(license) static char const *const LICENSE = license
+#define MODULE_DESCRIPTION(description) \
+ static char const *const DESCRIPTION = description
+
+#endif // LINUX_MODULE_H_
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/string.h b/src/zstd/contrib/linux-kernel/test/include/linux/string.h
new file mode 100644
index 000000000..3b2f59002
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/string.h
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/src/zstd/contrib/linux-kernel/test/include/linux/types.h b/src/zstd/contrib/linux-kernel/test/include/linux/types.h
new file mode 100644
index 000000000..c2d4f4b72
--- /dev/null
+++ b/src/zstd/contrib/linux-kernel/test/include/linux/types.h
@@ -0,0 +1,2 @@
+#include <stddef.h>
+#include <stdint.h>