mirror of
https://github.com/facebook/zstd.git
synced 2025-07-30 22:23:13 +03:00
Add linux-kernel freestanding
This commit is contained in:
1
contrib/linux-kernel/test/.gitignore
vendored
1
contrib/linux-kernel/test/.gitignore
vendored
@ -1 +0,0 @@
|
||||
*Test
|
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
@ -1,43 +1,28 @@
|
||||
|
||||
IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include -isystem ../../../lib/common/
|
||||
LINUX := ../linux
|
||||
LINUX_ZSTDLIB := $(LINUX)/lib/zstd
|
||||
|
||||
SOURCES := $(wildcard ../lib/zstd/*.c)
|
||||
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
|
||||
CPPFLAGS += -I$(LINUX)/include -I$(LINUX_ZSTDLIB) -Iinclude -DNDEBUG
|
||||
# Don't poison the workspace, it currently doesn't work with static allocation and workspace reuse
|
||||
CPPFLAGS += -DZSTD_ASAN_DONT_POISON_WORKSPACE
|
||||
|
||||
ARFLAGS := rcs
|
||||
CXXFLAGS += -std=c++11 -g -O3 -Wcast-align
|
||||
CFLAGS += -g -O3 -Wframe-larger-than=400 -Wcast-align
|
||||
CPPFLAGS += $(IFLAGS)
|
||||
LINUX_ZSTD_COMMON := $(wildcard $(LINUX_ZSTDLIB)/common/*.c)
|
||||
LINUX_ZSTD_COMPRESS := $(wildcard $(LINUX_ZSTDLIB)/compress/*.c)
|
||||
LINUX_ZSTD_DECOMPRESS := $(wildcard $(LINUX_ZSTDLIB)/decompress/*.c)
|
||||
LINUX_ZSTD_FILES := $(LINUX_ZSTD_COMMON) $(LINUX_ZSTD_COMPRESS) $(LINUX_ZSTD_DECOMPRESS)
|
||||
LINUX_ZSTD_OBJECTS := $(LINUX_ZSTD_FILES:.c=.o)
|
||||
|
||||
../lib/zstd/libzstd.a: $(OBJECTS)
|
||||
liblinuxzstd.a: $(LINUX_ZSTD_OBJECTS)
|
||||
$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
DecompressCrash: DecompressCrash.o $(OBJECTS) libFuzzer.a
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ -o $@
|
||||
test: test.c liblinuxzstd.a
|
||||
$(CC) $(LDFLAGS) $(CPPFLAGS) $(CFLAGS) $^ -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)
|
||||
run-test: test
|
||||
./test
|
||||
|
||||
.PHONY:
|
||||
clean:
|
||||
$(RM) -f *.{o,a} ../lib/zstd/*.{o,a} ../lib/*.o
|
||||
$(RM) -f DecompressCrash RoundTripCrash UserlandTest XXHashUserlandTest
|
||||
$(RM) -f $(LINUX_ZSTDLIB)/**/*.o
|
||||
$(RM) -f *.o *.a
|
||||
$(RM) -f test
|
||||
|
@ -1,162 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
@ -1,565 +0,0 @@
|
||||
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);
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
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());
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#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_
|
@ -1,6 +1,15 @@
|
||||
#ifndef LINUX_ERRNO_H_
|
||||
#define LINUX_ERRNO_H_
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_ERRNO_H
|
||||
#define LINUX_ERRNO_H
|
||||
|
||||
#define EINVAL 22
|
||||
|
||||
#endif // LINUX_ERRNO_H_
|
||||
#endif
|
||||
|
@ -1,16 +1,15 @@
|
||||
#ifndef LINUX_KERNEL_H_
|
||||
#define LINUX_KERNEL_H_
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#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 WARN_ON(x)
|
||||
|
||||
#define PTR_ALIGN(p, a) (typeof(p))ALIGN((unsigned long long)(p), (a))
|
||||
|
||||
#define current Something that doesn't compile :)
|
||||
|
||||
#endif // LINUX_KERNEL_H_
|
||||
#endif
|
||||
|
15
contrib/linux-kernel/test/include/linux/limits.h
Normal file
15
contrib/linux-kernel/test/include/linux/limits.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_LIMITS_H
|
||||
#define LINUX_LIMITS_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#endif
|
@ -1,11 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#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;
|
||||
}
|
||||
#define div_u64(dividend, divisor) ((dividend) / (divisor))
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,14 @@
|
||||
#ifndef LINUX_MODULE_H_
|
||||
#define LINUX_MODULE_H_
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_MODULE_H
|
||||
#define LINUX_MODULE_H
|
||||
|
||||
#define EXPORT_SYMBOL(symbol) \
|
||||
void* __##symbol = symbol
|
||||
@ -7,4 +16,4 @@
|
||||
#define MODULE_DESCRIPTION(description) \
|
||||
static char const *const DESCRIPTION = description
|
||||
|
||||
#endif // LINUX_MODULE_H_
|
||||
#endif
|
||||
|
15
contrib/linux-kernel/test/include/linux/printk.h
Normal file
15
contrib/linux-kernel/test/include/linux/printk.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_PRINTK_H
|
||||
#define LINUX_PRINTK_H
|
||||
|
||||
#define pr_debug(...)
|
||||
|
||||
#endif
|
15
contrib/linux-kernel/test/include/linux/stddef.h
Normal file
15
contrib/linux-kernel/test/include/linux/stddef.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_STDDEF_H
|
||||
#define LINUX_STDDEF_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#endif
|
@ -1 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_STRING_H
|
||||
#define LINUX_STRING_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#endif
|
||||
|
@ -1,2 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#ifndef LINUX_TYPES_H
|
||||
#define LINUX_TYPES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#endif
|
||||
|
747
contrib/linux-kernel/test/include/linux/xxhash.h
Normal file
747
contrib/linux-kernel/test/include/linux/xxhash.h
Normal file
@ -0,0 +1,747 @@
|
||||
/*
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet.
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/*
|
||||
* Notice extracted from xxHash homepage:
|
||||
*
|
||||
* xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
* It also successfully passes all tests from the SMHasher suite.
|
||||
*
|
||||
* Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2
|
||||
* Duo @3GHz)
|
||||
*
|
||||
* Name Speed Q.Score Author
|
||||
* xxHash 5.4 GB/s 10
|
||||
* CrapWow 3.2 GB/s 2 Andrew
|
||||
* MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
* SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
* SBox 1.4 GB/s 9 Bret Mulvey
|
||||
* Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
* SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
* CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
* FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
* CRC32 0.43 GB/s 9
|
||||
* MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
* SHA1-32 0.28 GB/s 10
|
||||
*
|
||||
* Q.Score is a measure of quality of the hash function.
|
||||
* It depends on successfully passing SMHasher test set.
|
||||
* 10 is a perfect score.
|
||||
*
|
||||
* A 64-bits version, named xxh64 offers much better speed,
|
||||
* but for 64-bits applications only.
|
||||
* Name Speed on 64 bits Speed on 32 bits
|
||||
* xxh64 13.8 GB/s 1.9 GB/s
|
||||
* xxh32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H
|
||||
#define XXHASH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define XXH_API static inline __attribute__((unused))
|
||||
/*-****************************
|
||||
* Simple Hash Functions
|
||||
*****************************/
|
||||
|
||||
/**
|
||||
* xxh32() - calculate the 32-bit hash of the input with a given seed.
|
||||
*
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
*
|
||||
* Return: The 32-bit hash of the data.
|
||||
*/
|
||||
XXH_API uint32_t xxh32(const void *input, size_t length, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh64() - calculate the 64-bit hash of the input with a given seed.
|
||||
*
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* This function runs 2x faster on 64-bit systems, but slower on 32-bit systems.
|
||||
*
|
||||
* Return: The 64-bit hash of the data.
|
||||
*/
|
||||
XXH_API uint64_t xxh64(const void *input, size_t length, uint64_t seed);
|
||||
|
||||
/**
|
||||
* xxhash() - calculate wordsize hash of the input with a given seed
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* If the hash does not need to be comparable between machines with
|
||||
* different word sizes, this function will call whichever of xxh32()
|
||||
* or xxh64() is faster.
|
||||
*
|
||||
* Return: wordsize hash of the data.
|
||||
*/
|
||||
|
||||
static inline unsigned long xxhash(const void *input, size_t length,
|
||||
uint64_t seed)
|
||||
{
|
||||
#if BITS_PER_LONG == 64
|
||||
return xxh64(input, length, seed);
|
||||
#else
|
||||
return xxh32(input, length, seed);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*-****************************
|
||||
* Streaming Hash Functions
|
||||
*****************************/
|
||||
|
||||
/*
|
||||
* These definitions are only meant to allow allocation of XXH state
|
||||
* statically, on stack, or in a struct for example.
|
||||
* Do not use members directly.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct xxh32_state - private xxh32 state, do not use members directly
|
||||
*/
|
||||
struct xxh32_state {
|
||||
uint32_t total_len_32;
|
||||
uint32_t large_len;
|
||||
uint32_t v1;
|
||||
uint32_t v2;
|
||||
uint32_t v3;
|
||||
uint32_t v4;
|
||||
uint32_t mem32[4];
|
||||
uint32_t memsize;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xxh32_state - private xxh64 state, do not use members directly
|
||||
*/
|
||||
struct xxh64_state {
|
||||
uint64_t total_len;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t v4;
|
||||
uint64_t mem64[4];
|
||||
uint32_t memsize;
|
||||
};
|
||||
|
||||
/**
|
||||
* xxh32_reset() - reset the xxh32 state to start a new hashing operation
|
||||
*
|
||||
* @state: The xxh32 state to reset.
|
||||
* @seed: Initialize the hash state with this seed.
|
||||
*
|
||||
* Call this function on any xxh32_state to prepare for a new hashing operation.
|
||||
*/
|
||||
XXH_API void xxh32_reset(struct xxh32_state *state, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh32_update() - hash the data given and update the xxh32 state
|
||||
*
|
||||
* @state: The xxh32 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh32_reset() call xxh32_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
XXH_API int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh32_digest() - produce the current xxh32 hash
|
||||
*
|
||||
* @state: Produce the current xxh32 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh32_digest(), and
|
||||
* generate new hashes later on, by calling xxh32_digest() again.
|
||||
*
|
||||
* Return: The xxh32 hash stored in the state.
|
||||
*/
|
||||
XXH_API uint32_t xxh32_digest(const struct xxh32_state *state);
|
||||
|
||||
/**
|
||||
* xxh64_reset() - reset the xxh64 state to start a new hashing operation
|
||||
*
|
||||
* @state: The xxh64 state to reset.
|
||||
* @seed: Initialize the hash state with this seed.
|
||||
*/
|
||||
XXH_API void xxh64_reset(struct xxh64_state *state, uint64_t seed);
|
||||
|
||||
/**
|
||||
* xxh64_update() - hash the data given and update the xxh64 state
|
||||
* @state: The xxh64 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh64_reset() call xxh64_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
XXH_API int xxh64_update(struct xxh64_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh64_digest() - produce the current xxh64 hash
|
||||
*
|
||||
* @state: Produce the current xxh64 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh64_digest(), and
|
||||
* generate new hashes later on, by calling xxh64_digest() again.
|
||||
*
|
||||
* Return: The xxh64 hash stored in the state.
|
||||
*/
|
||||
XXH_API uint64_t xxh64_digest(const struct xxh64_state *state);
|
||||
|
||||
/*-**************************
|
||||
* Utils
|
||||
***************************/
|
||||
|
||||
/**
|
||||
* xxh32_copy_state() - copy the source state into the destination state
|
||||
*
|
||||
* @src: The source xxh32 state.
|
||||
* @dst: The destination xxh32 state.
|
||||
*/
|
||||
XXH_API void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
|
||||
|
||||
/**
|
||||
* xxh64_copy_state() - copy the source state into the destination state
|
||||
*
|
||||
* @src: The source xxh64 state.
|
||||
* @dst: The destination xxh64 state.
|
||||
*/
|
||||
XXH_API void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
|
||||
|
||||
/*
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet.
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/xxhash.h>
|
||||
|
||||
/*-*************************************
|
||||
* Macros
|
||||
**************************************/
|
||||
#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
|
||||
#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
# define XXH_CPU_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# define XXH_CPU_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/*-*************************************
|
||||
* Constants
|
||||
**************************************/
|
||||
static const uint32_t PRIME32_1 = 2654435761U;
|
||||
static const uint32_t PRIME32_2 = 2246822519U;
|
||||
static const uint32_t PRIME32_3 = 3266489917U;
|
||||
static const uint32_t PRIME32_4 = 668265263U;
|
||||
static const uint32_t PRIME32_5 = 374761393U;
|
||||
|
||||
static const uint64_t PRIME64_1 = 11400714785074694791ULL;
|
||||
static const uint64_t PRIME64_2 = 14029467366897019727ULL;
|
||||
static const uint64_t PRIME64_3 = 1609587929392839161ULL;
|
||||
static const uint64_t PRIME64_4 = 9650029242287828579ULL;
|
||||
static const uint64_t PRIME64_5 = 2870177450012600261ULL;
|
||||
|
||||
/*-**************************
|
||||
* Utils
|
||||
***************************/
|
||||
XXH_API void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
XXH_API void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
/*-***************************
|
||||
* Simple Hash Functions
|
||||
****************************/
|
||||
static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
|
||||
{
|
||||
seed += input * PRIME32_2;
|
||||
seed = xxh_rotl32(seed, 13);
|
||||
seed *= PRIME32_1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
XXH_API uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *b_end = p + len;
|
||||
uint32_t h32;
|
||||
|
||||
if (len >= 16) {
|
||||
const uint8_t *const limit = b_end - 16;
|
||||
uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
uint32_t v2 = seed + PRIME32_2;
|
||||
uint32_t v3 = seed + 0;
|
||||
uint32_t v4 = seed - PRIME32_1;
|
||||
|
||||
do {
|
||||
v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
} while (p <= limit);
|
||||
|
||||
h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
|
||||
xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
|
||||
} else {
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (uint32_t)len;
|
||||
|
||||
while (p + 4 <= b_end) {
|
||||
h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
|
||||
{
|
||||
acc += input * PRIME64_2;
|
||||
acc = xxh_rotl64(acc, 31);
|
||||
acc *= PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
|
||||
{
|
||||
val = xxh64_round(0, val);
|
||||
acc ^= val;
|
||||
acc = acc * PRIME64_1 + PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
XXH_API uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
uint64_t h64;
|
||||
|
||||
if (len >= 32) {
|
||||
const uint8_t *const limit = b_end - 32;
|
||||
uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
uint64_t v2 = seed + PRIME64_2;
|
||||
uint64_t v3 = seed + 0;
|
||||
uint64_t v4 = seed - PRIME64_1;
|
||||
|
||||
do {
|
||||
v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
} while (p <= limit);
|
||||
|
||||
h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
h64 = xxh64_merge_round(h64, v1);
|
||||
h64 = xxh64_merge_round(h64, v2);
|
||||
h64 = xxh64_merge_round(h64, v3);
|
||||
h64 = xxh64_merge_round(h64, v4);
|
||||
|
||||
} else {
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (uint64_t)len;
|
||||
|
||||
while (p + 8 <= b_end) {
|
||||
const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
|
||||
h64 ^= k1;
|
||||
h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (p + 4 <= b_end) {
|
||||
h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
/*-**************************************************
|
||||
* Advanced Hash Functions
|
||||
***************************************************/
|
||||
XXH_API void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
|
||||
{
|
||||
/* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
struct xxh32_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state.v2 = seed + PRIME32_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME32_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
}
|
||||
|
||||
XXH_API void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
|
||||
{
|
||||
/* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
struct xxh64_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state.v2 = seed + PRIME64_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME64_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
}
|
||||
|
||||
XXH_API int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state->total_len_32 += (uint32_t)len;
|
||||
state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
|
||||
|
||||
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* some data left from previous update */
|
||||
const uint32_t *p32 = state->mem32;
|
||||
|
||||
memcpy((uint8_t *)(state->mem32) + state->memsize, input,
|
||||
16 - state->memsize);
|
||||
|
||||
state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= b_end - 16) {
|
||||
const uint8_t *const limit = b_end - 16;
|
||||
uint32_t v1 = state->v1;
|
||||
uint32_t v2 = state->v2;
|
||||
uint32_t v3 = state->v3;
|
||||
uint32_t v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
} while (p <= limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < b_end) {
|
||||
memcpy(state->mem32, p, (size_t)(b_end-p));
|
||||
state->memsize = (uint32_t)(b_end-p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XXH_API uint32_t xxh32_digest(const struct xxh32_state *state)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)state->mem32;
|
||||
const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
|
||||
state->memsize;
|
||||
uint32_t h32;
|
||||
|
||||
if (state->large_len) {
|
||||
h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
|
||||
xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
|
||||
} else {
|
||||
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += state->total_len_32;
|
||||
|
||||
while (p + 4 <= b_end) {
|
||||
h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
XXH_API int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* tmp buffer is full */
|
||||
uint64_t *p64 = state->mem64;
|
||||
|
||||
memcpy(((uint8_t *)p64) + state->memsize, input,
|
||||
32 - state->memsize);
|
||||
|
||||
state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
|
||||
|
||||
p += 32 - state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p + 32 <= b_end) {
|
||||
const uint8_t *const limit = b_end - 32;
|
||||
uint64_t v1 = state->v1;
|
||||
uint64_t v2 = state->v2;
|
||||
uint64_t v3 = state->v3;
|
||||
uint64_t v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
} while (p <= limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < b_end) {
|
||||
memcpy(state->mem64, p, (size_t)(b_end-p));
|
||||
state->memsize = (uint32_t)(b_end - p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XXH_API uint64_t xxh64_digest(const struct xxh64_state *state)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)state->mem64;
|
||||
const uint8_t *const b_end = (const uint8_t *)state->mem64 +
|
||||
state->memsize;
|
||||
uint64_t h64;
|
||||
|
||||
if (state->total_len >= 32) {
|
||||
const uint64_t v1 = state->v1;
|
||||
const uint64_t v2 = state->v2;
|
||||
const uint64_t v3 = state->v3;
|
||||
const uint64_t v4 = state->v4;
|
||||
|
||||
h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
h64 = xxh64_merge_round(h64, v1);
|
||||
h64 = xxh64_merge_round(h64, v2);
|
||||
h64 = xxh64_merge_round(h64, v3);
|
||||
h64 = xxh64_merge_round(h64, v4);
|
||||
} else {
|
||||
h64 = state->v3 + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (uint64_t)state->total_len;
|
||||
|
||||
while (p + 8 <= b_end) {
|
||||
const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
|
||||
h64 ^= k1;
|
||||
h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (p + 4 <= b_end) {
|
||||
h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
#endif /* XXHASH_H */
|
211
contrib/linux-kernel/test/test.c
Normal file
211
contrib/linux-kernel/test/test.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 7-2020, 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).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/zstd.h>
|
||||
|
||||
#define CONTROL(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
fprintf(stderr, "%s:%u: %s failed!\n", __FUNCTION__, __LINE__, #x); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
char *data2;
|
||||
size_t dataSize;
|
||||
char *comp;
|
||||
size_t compSize;
|
||||
} test_data_t;
|
||||
|
||||
test_data_t create_test_data(void) {
|
||||
test_data_t data;
|
||||
data.dataSize = 128 * 1024;
|
||||
data.data = malloc(data.dataSize);
|
||||
CONTROL(data.data != NULL);
|
||||
data.data2 = malloc(data.dataSize);
|
||||
CONTROL(data.data2 != NULL);
|
||||
data.compSize = ZSTD_compressBound(data.dataSize);
|
||||
data.comp = malloc(data.compSize);
|
||||
CONTROL(data.comp != NULL);
|
||||
memset(data.data, 0, data.dataSize);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void free_test_data(test_data_t const *data) {
|
||||
free(data->data);
|
||||
free(data->data2);
|
||||
free(data->comp);
|
||||
}
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static void test_btrfs(test_data_t const *data) {
|
||||
fprintf(stderr, "testing btrfs use cases... ");
|
||||
size_t const size = MIN(data->dataSize, 128 * 1024);
|
||||
for (int level = -1; level < 16; ++level) {
|
||||
ZSTD_parameters params = ZSTD_getParams(level, size, 0);
|
||||
CONTROL(params.cParams.windowLog <= 17);
|
||||
size_t const workspaceSize =
|
||||
MAX(ZSTD_estimateCStreamSize_usingCParams(params.cParams),
|
||||
ZSTD_estimateDStreamSize(size));
|
||||
void *workspace = malloc(workspaceSize);
|
||||
CONTROL(workspace != NULL);
|
||||
|
||||
char const *ip = data->data;
|
||||
char const *iend = ip + size;
|
||||
char *op = data->comp;
|
||||
char *oend = op + data->compSize;
|
||||
{
|
||||
ZSTD_CStream *cctx = ZSTD_initStaticCStream(workspace, workspaceSize);
|
||||
CONTROL(cctx != NULL);
|
||||
CONTROL(!ZSTD_isError(
|
||||
ZSTD_initCStream_advanced(cctx, NULL, 0, params, size)));
|
||||
ZSTD_outBuffer out = {NULL, 0, 0};
|
||||
ZSTD_inBuffer in = {NULL, 0, 0};
|
||||
for (;;) {
|
||||
if (in.pos == in.size) {
|
||||
in.src = ip;
|
||||
in.size = MIN(4096, iend - ip);
|
||||
in.pos = 0;
|
||||
ip += in.size;
|
||||
}
|
||||
|
||||
if (out.pos == out.size) {
|
||||
out.dst = op;
|
||||
out.size = MIN(4096, oend - op);
|
||||
out.pos = 0;
|
||||
op += out.size;
|
||||
}
|
||||
|
||||
if (ip != iend || in.pos < in.size) {
|
||||
CONTROL(!ZSTD_isError(ZSTD_compressStream(cctx, &out, &in)));
|
||||
} else {
|
||||
size_t const ret = ZSTD_endStream(cctx, &out);
|
||||
CONTROL(!ZSTD_isError(ret));
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
op += out.pos;
|
||||
}
|
||||
|
||||
ip = data->comp;
|
||||
iend = op;
|
||||
op = data->data2;
|
||||
oend = op + size;
|
||||
{
|
||||
ZSTD_DStream *dctx = ZSTD_initStaticDStream(workspace, workspaceSize);
|
||||
CONTROL(dctx != NULL);
|
||||
ZSTD_outBuffer out = {NULL, 0, 0};
|
||||
ZSTD_inBuffer in = {NULL, 0, 0};
|
||||
for (;;) {
|
||||
if (in.pos == in.size) {
|
||||
in.src = ip;
|
||||
in.size = MIN(4096, iend - ip);
|
||||
in.pos = 0;
|
||||
ip += in.size;
|
||||
}
|
||||
|
||||
if (out.pos == out.size) {
|
||||
out.dst = op;
|
||||
out.size = MIN(4096, oend - op);
|
||||
out.pos = 0;
|
||||
op += out.size;
|
||||
}
|
||||
|
||||
size_t const ret = ZSTD_decompressStream(dctx, &out, &in);
|
||||
CONTROL(!ZSTD_isError(ret));
|
||||
if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CONTROL(op - data->data2 == data->dataSize);
|
||||
CONTROL(!memcmp(data->data, data->data2, data->dataSize));
|
||||
free(workspace);
|
||||
}
|
||||
fprintf(stderr, "Ok\n");
|
||||
}
|
||||
|
||||
static void test_decompress_unzstd(test_data_t const *data) {
|
||||
fprintf(stderr, "Testing decompress unzstd... ");
|
||||
size_t cSize;
|
||||
{
|
||||
size_t const wkspSize = ZSTD_estimateCCtxSize(19);
|
||||
void* wksp = malloc(wkspSize);
|
||||
CONTROL(wksp != NULL);
|
||||
ZSTD_CCtx* cctx = ZSTD_initStaticCCtx(wksp, wkspSize);
|
||||
CONTROL(cctx != NULL);
|
||||
cSize = ZSTD_compressCCtx(cctx, data->comp, data->compSize, data->data, data->dataSize, 19);
|
||||
CONTROL(!ZSTD_isError(cSize));
|
||||
free(wksp);
|
||||
}
|
||||
{
|
||||
size_t const wkspSize = ZSTD_estimateDCtxSize();
|
||||
void* wksp = malloc(wkspSize);
|
||||
CONTROL(wksp != NULL);
|
||||
ZSTD_DCtx* dctx = ZSTD_initStaticDCtx(wksp, wkspSize);
|
||||
CONTROL(dctx != NULL);
|
||||
size_t const dSize = ZSTD_decompressDCtx(dctx, data->data2, data->dataSize, data->comp, cSize);
|
||||
CONTROL(!ZSTD_isError(dSize));
|
||||
CONTROL(dSize == data->dataSize);
|
||||
CONTROL(!memcmp(data->data, data->data2, data->dataSize));
|
||||
free(wksp);
|
||||
}
|
||||
fprintf(stderr, "Ok\n");
|
||||
}
|
||||
|
||||
static char *g_stack = NULL;
|
||||
|
||||
static void __attribute__((noinline)) use(void *x) {
|
||||
asm volatile("" : "+r"(x));
|
||||
}
|
||||
|
||||
static void __attribute__((noinline)) set_stack() {
|
||||
|
||||
char stack[8192];
|
||||
g_stack = stack;
|
||||
memset(g_stack, 0x33, 8192);
|
||||
use(g_stack);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline)) check_stack() {
|
||||
size_t cleanStack = 0;
|
||||
while (cleanStack < 8192 && g_stack[cleanStack] == 0x33) {
|
||||
++cleanStack;
|
||||
}
|
||||
size_t const stackSize = 8192 - cleanStack;
|
||||
fprintf(stderr, "Maximum stack size: %zu\n", stackSize);
|
||||
CONTROL(stackSize <= 2048 + 512);
|
||||
}
|
||||
|
||||
static void test_stack_usage(test_data_t const *data) {
|
||||
set_stack();
|
||||
test_btrfs(data);
|
||||
test_decompress_unzstd(data);
|
||||
check_stack();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_data_t data = create_test_data();
|
||||
test_btrfs(&data);
|
||||
test_decompress_unzstd(&data);
|
||||
test_stack_usage(&data);
|
||||
free_test_data(&data);
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user