diff --git a/.github/workflows/dev-short-tests.yml b/.github/workflows/dev-short-tests.yml index 8e8753658..31d44542f 100644 --- a/.github/workflows/dev-short-tests.yml +++ b/.github/workflows/dev-short-tests.yml @@ -435,6 +435,8 @@ jobs: make clean LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests + CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j check + CFLAGS="-march=armv8.2-a+sve2" LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make -j -C tests test-cli-tests # This test is only compatible with standard libraries that support BTI (Branch Target Identification). # Unfortunately, the standard library provided on Ubuntu 24.04 does not have this feature enabled. # make clean diff --git a/tests/cli-tests/run.py b/tests/cli-tests/run.py index 011c8478e..0addd6b1a 100755 --- a/tests/cli-tests/run.py +++ b/tests/cli-tests/run.py @@ -640,7 +640,7 @@ if __name__ == "__main__": help="Preserve the scratch directory TEST_DIR/scratch/ for debugging purposes." ) parser.add_argument("--verbose", action="store_true", help="Verbose test output.") - parser.add_argument("--timeout", default=200, type=int, help="Test case timeout in seconds. Set to 0 to disable timeouts.") + parser.add_argument("--timeout", default=800, type=int, help="Test case timeout in seconds. Set to 0 to disable timeouts.") parser.add_argument( "--exec-prefix", default=None, diff --git a/tests/fuzzer.c b/tests/fuzzer.c index b74460bb5..da380aced 100644 --- a/tests/fuzzer.c +++ b/tests/fuzzer.c @@ -44,6 +44,13 @@ /* must be included after util.h, due to ERROR macro redefinition issue on Visual Studio */ #include "zstd_internal.h" /* ZSTD_WORKSPACETOOLARGE_MAXDURATION, ZSTD_WORKSPACETOOLARGE_FACTOR, KB, MB */ #include "threading.h" /* ZSTD_pthread_create, ZSTD_pthread_join */ +#include "compress/hist.h" /* HIST_count_wksp */ + + +/*-************************************ +* Macros +**************************************/ +#define COUNTOF(array) (sizeof(array) / sizeof(*(array))) /*-************************************ @@ -567,6 +574,123 @@ static void test_decompressBound(unsigned tnb) DISPLAYLEVEL(3, "OK \n"); } +static unsigned test_histCountWksp(unsigned seed, unsigned testNb) +{ + static const unsigned symLowLimits[] = { 0, 27, 0, 0, 27, 42, 0, 0, 27, 42, 27, 42 }; + static const unsigned symHighLimits[] = { 255, 255, 210, 110, 42, 42, 210, 110, 42, 42, 42, 42 }; + static const unsigned symMaxLimits[] = { 255, 255, 255, 255, 255, 255, 230, 130, 99, 99, 42, 42 }; + static const size_t inputSizes[] = { 3367, 1761, 893, 117 }; + unsigned workspace[HIST_WKSP_SIZE_U32]; + size_t res, i, is, il; + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with empty source : ", testNb++); + { + /* With NULL source UBSan of older Clang could fail: applying zero offset to null pointer. */ + static const unsigned char source[4] = { 0 }; + unsigned count[1] = { 0 }; + unsigned maxSym = 0; + res = HIST_count_wksp(count, &maxSym, source, 0, workspace, sizeof(workspace)); + CHECK_EQ(res, 0); + CHECK_EQ(maxSym, 0); + CHECK_EQ(count[0], 0); + } + DISPLAYLEVEL(3, "OK \n"); + +#if HIST_WKSP_SIZE_U32 + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with small workspace : ", testNb++); + { + unsigned count[1] = { 0 }; + unsigned maxSym = 0; + res = HIST_count_wksp(count, &maxSym, NULL, 0, workspace, sizeof(workspace) - 1); + CHECK_EQ(res, ERROR(workSpace_tooSmall)); + CHECK_EQ(maxSym, 0); + CHECK_EQ(count[0], 0); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with wrong workspace alignment : ", testNb++); + { + unsigned count[1] = { 0 }; + unsigned maxSym = 0; + res = HIST_count_wksp(count, &maxSym, NULL, 0, (unsigned*)(void*)((char*)workspace + 1), sizeof(workspace)); + CHECK_EQ(res, ERROR(GENERIC)); + CHECK_EQ(maxSym, 0); + CHECK_EQ(count[0], 0); + } + DISPLAYLEVEL(3, "OK \n"); +#endif + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with symbol out of range, small size : ", testNb++); + { + /* For less elements HIST_count_parallel_wksp would fail. */ + static const unsigned char source[4] = { 1, 4, 0, 2 }; + static const unsigned expected[6] = { 0 }; + unsigned count[6] = { 0 }; + unsigned maxSym = 2; + res = HIST_count_wksp(count, &maxSym, source, sizeof(source), workspace, sizeof(workspace)); + CHECK_EQ(res, ERROR(maxSymbolValue_tooSmall)); + CHECK_EQ(maxSym, 2); + for (i = 0; i < COUNTOF(expected); ++i) CHECK_EQ(count[i], expected[i]); + } + DISPLAYLEVEL(3, "OK \n"); + + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp with symbol out of range, medium size : ", testNb++); + { + unsigned char source[3407]; + unsigned count[6] = { 0 }; + unsigned maxSym = 2; + for (i = 0; i < COUNTOF(source); ++i) { + source[i] = (48271 * (i + 1)) & 3; + } + res = HIST_count_wksp(count, &maxSym, source, sizeof(source), workspace, sizeof(workspace)); + CHECK_EQ(res, ERROR(maxSymbolValue_tooSmall)); + CHECK_EQ(maxSym, 2); + for (i = 0; i < COUNTOF(count); ++i) CHECK_EQ(count[i], 0); + } + DISPLAYLEVEL(3, "OK \n"); + + for (il = 0; il < COUNTOF(symMaxLimits); ++il) { + unsigned symMax = symMaxLimits[il]; + unsigned symLow = symLowLimits[il]; + unsigned symHigh = symHighLimits[il]; + unsigned symRange = symHigh - symLow + 1; + + for (is = 0; is < COUNTOF(inputSizes); ++is) { + unsigned char source[4000]; + size_t inputSize = inputSizes[is]; + assert(inputSize <= sizeof(source)); + DISPLAYLEVEL(3, "test%3u : HIST_count_wksp test in [%u..%u], symMax: %u, inputSize: %u : ", + testNb++, symLow, symHigh, symMax, (unsigned)inputSize); + { + unsigned count[260] = { 0 }; + unsigned expected[COUNTOF(count)] = { 0 }; + unsigned maxSym = symMax; + unsigned realMaxSym = symMax; + unsigned maxCount = 0; + for (i = 0; i < inputSize; ++i) { + unsigned prng = (48271 * (i + seed)) % symRange + symLow; + source[i] = (unsigned char)prng; + ++expected[prng]; + } + /* for basic buffer overwrite checks */ + for (i = maxSym + 1; i < COUNTOF(count); ++i) expected[i] = count[i] = ~0u; + for (i = 0; i <= maxSym; ++i) maxCount = MAX(maxCount, expected[i]); + for (i = realMaxSym; i > 0; --i) { + if (expected[i]) break; + --realMaxSym; + } + res = HIST_count_wksp(count, &maxSym, source, inputSize, workspace, sizeof(workspace)); + CHECK_EQ(res, maxCount); + CHECK_EQ(maxSym, realMaxSym); + for (i = 0; i < COUNTOF(expected); ++i) CHECK_EQ(count[i], expected[i]); + } + DISPLAYLEVEL(3, "OK \n"); + } + } + + return testNb; +} + static void test_setCParams(unsigned tnb) { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); @@ -712,6 +836,8 @@ static int basicUnitTests(U32 const seed, double compressibility) } DISPLAYLEVEL(3, "OK \n"); + testNb = test_histCountWksp(seed, testNb); + DISPLAYLEVEL(3, "test%3u : compress %u bytes : ", testNb++, (unsigned)CNBuffSize); { ZSTD_CCtx* const cctx = ZSTD_createCCtx(); if (cctx==NULL) goto _output_error;