Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
19d806e
reject out-of-range numFrames in seekable seek table loader
saleemno1 Jul 29, 2026
7d777bb
Reject a too large block in ZSTD_compressSequencesAndLiterals()
nileshpatil6 Aug 21, 2026
bf7504b
tests: rename cSize in the new test to avoid shadowing
nileshpatil6 Aug 22, 2026
61da23a
Enforce literal buffer capacity contract
KSAGlory Sep 11, 2026
5641f82
cmake: fix CXX flag dependency in AddZstdCompilationFlags when C++ is…
Tyagiquamar Oct 1, 2026
81c4414
decompress: drop the DDict hashset on ZSTD_DCtx_reset and ZSTD_DCtx_r…
filtede98 Oct 5, 2026
e47dfb3
programs: fix zstd -l infinite loop on a large skippable frame
ilyas-mallah Oct 9, 2026
ed26f94
compress: wait for an abandoned frame's jobs before freeing what they…
Eshan05 Oct 28, 2026
c70f728
ci: run the macOS ARM64 CMake job on macos-latest
Cyan4973 Nov 7, 2026
825bfe8
Merge pull request #4904 from meta/ci-macos-arm64-runner
Cyan4973 Nov 7, 2026
b276bea
programs: apply --memory to .xz and .lzma decompression
Cyan4973 Nov 7, 2026
5633b0e
Merge pull request #4903 from meta/cli-lzma-memlimit
Cyan4973 Nov 7, 2026
399405a
Merge pull request #4717 from saleemno1/seektable-numframes-overflow
Cyan4973 Nov 8, 2026
8b985c5
Merge pull request #4833 from ilyas-mallah/cli-list-skippable-overflow
Cyan4973 Nov 8, 2026
6bdc1d3
programs: don't follow symbolic links and junctions in -r on Windows
Cyan4973 Nov 8, 2026
4b0e377
Merge pull request #4905 from meta/windows-recursive-skip-links
Cyan4973 Nov 8, 2026
f9c9c68
seekable_format: Reject offsets past the end in decompress
eyupcanakman Nov 6, 2026
75aeac4
decompress: reject output overrunning split literals and oversized bl…
terrelln Nov 5, 2026
6c93b99
seekable_format: document ZSTD_seekable_decompress() at the end of th…
Cyan4973 Nov 9, 2026
e6bd22d
Merge pull request #4902 from eyupcanakman/seekable-decompress-past-end
Cyan4973 Nov 9, 2026
cec5da4
programs: don't write the output through a symbolic link
Cyan4973 Nov 9, 2026
cc53693
Merge pull request #4906 from meta/cli-dst-no-follow
Cyan4973 Nov 9, 2026
75dd154
doc: ZSTD_DCtx_refDDict() table is freed by reset and refDDict(NULL)
Cyan4973 Nov 10, 2026
fd1f65c
tests: shorten the DDict hashset reset test
Cyan4973 Nov 10, 2026
3b8634e
Merge pull request #4792 from filtede98/fix-ddict-hashset-load-factor…
Cyan4973 Nov 10, 2026
54ade3a
compress: wait for an empty job before releasing it
Cyan4973 Nov 10, 2026
a8af53b
compress: clear jobReady when the jobs are released
Cyan4973 Nov 10, 2026
8136851
tests: shorten the abandoned multi-threaded frame test
Cyan4973 Nov 10, 2026
ad2018c
Merge pull request #4871 from Eshan05/fix-mt-abandoned-frame
Cyan4973 Nov 10, 2026
7e877d8
[zstd] Fix typo in spec
terrelln May 18, 2026
a2026f9
compress: stop using the previous pool after ZSTD_CCtx_refThreadPool()
Cyan4973 Nov 10, 2026
31db1af
compress: don't resize a thread pool provided by the application
Cyan4973 Nov 10, 2026
c2095c7
Merge pull request #4917 from meta/thread-pool-rebind
Cyan4973 Nov 10, 2026
c3e2c0d
Fix out-of-bounds read in FASTCOVER on small training samples (#4710)
eyupcanakman Nov 10, 2026
39ec354
Fix size_t underflow in COVER_ctx_init for small training sets (#4690)
rohitsux Nov 10, 2026
7bc5369
tests: shorten the too large block test
Cyan4973 Nov 10, 2026
918ade2
zstd.h: state the block size limit of ZSTD_compressSequencesAndLitera…
Cyan4973 Nov 10, 2026
ac5660c
dictBuilder: break COVER sort ties by position, not by address (#4765)
jaypatrickhoward Nov 10, 2026
35a056a
Revert "Fix size_t underflow in COVER_ctx_init for small training set…
kevinjzhang Nov 10, 2026
0113699
Fix size_t underflow in COVER_ctx_init for small training sets
rohitsux Jun 5, 2026
8fcf03f
Factor out COVER read length calculation
Nov 10, 2026
d166226
Merge branch 'dev' into fix/compress-sequences-and-literals-block-size
Cyan4973 Nov 10, 2026
4dde8bf
Fix legacy dictionary magic out-of-bounds reads
terrelln Nov 10, 2026
974238c
Fix block splitter partition bounds
terrelln Nov 10, 2026
a7b60c8
Merge pull request #4741 from nileshpatil6/fix/compress-sequences-and…
Cyan4973 Nov 11, 2026
719e528
compress: validate repcodes against retained dictionary content
terrelln Nov 10, 2026
b09de2b
linux: state the lit_capacity margin of zstd_compress_sequences_and_l…
Cyan4973 Nov 11, 2026
4cf889e
Merge pull request #4782 from KSAGlory/fix/literal-capacity-contract
Cyan4973 Nov 11, 2026
18f8d17
cmake: detect clang with the C compiler id in lib/CMakeLists.txt
Cyan4973 Nov 11, 2026
8bcbe69
Merge pull request #4810 from Tyagiquamar/fix-cmake-cxx-flag-dep-4800
Cyan4973 Nov 11, 2026
e4b3d2c
dictBuilder: sort COVER dmers with a multi-key quicksort
jaypatrickhoward Sep 6, 2026
2c8ce5d
common: stop defining _GNU_SOURCE in zstd_deps.h
jaypatrickhoward Nov 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/cmake-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ jobs:
name: "Clang-CL"
runner: "windows-2022"
cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DZSTD_BUILD_TESTS=ON"
- generator: "Visual Studio 17 2022"
flags: "-T ClangCL"
name: "Clang-CL (No ZSTD_BUILD_TESTS)"
runner: "windows-2022"
# Intentionally omit ZSTD_BUILD_TESTS: C++ is not enabled, so only the C compiler id is set
cmake_extra_flags: "-DCMAKE_COMPILE_WARNING_AS_ERROR=ON"
- generator: "Visual Studio 17 2022"
flags: "-T ClangCL -A x64 -DCMAKE_C_FLAGS=/arch:AVX2"
name: "Clang-CL AVX2"
Expand Down Expand Up @@ -154,7 +160,7 @@ jobs:
# Uses native ARM64 hardware for optimal performance and compatibility testing
cmake-macos-arm64:
name: "CMake macOS ARM64 (Apple Silicon)"
runs-on: macos-14 # ARM64 runner
runs-on: macos-latest # ARM64 runner
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1
- name: "CMake build and test (ARM64)"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dev-short-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ jobs:
sudo apt install -y musl-tools
- name: Compile with musl-gcc and test-zstd
run: |
CC=musl-gcc CFLAGS="-Werror -O3" CPPFLAGS=-DZDICT_QSORT=ZDICT_QSORT_C90 make -j -C tests test-zstd V=1
CC=musl-gcc CFLAGS="-Werror -O3" make -j -C tests test-zstd V=1

intel-cet-compatibility:
runs-on: ubuntu-latest
Expand Down
36 changes: 18 additions & 18 deletions build/cmake/CMakeModules/AddZstdCompilationFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function(EnableCompilerFlag _flag _C _CXX _LD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flag}" PARENT_SCOPE)
endif ()
endif ()
if (_CXX AND CMAKE_CXX_COMPILER)
if (_CXX AND CMAKE_CXX_COMPILER_LOADED)
CHECK_CXX_COMPILER_FLAG(${_flag} CXX_FLAG_${varname})
if (CXX_FLAG_${varname})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}" PARENT_SCOPE)
Expand Down Expand Up @@ -56,42 +56,42 @@ macro(ADD_ZSTD_COMPILATION_FLAGS _C _CXX _LD)
# compiler flags to mark the stack as non-executable.
set(ZSTD_HAS_NOEXECSTACK false)

if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" OR MINGW) #Not only UNIX but also WIN32 for MinGW
if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" OR MINGW) #Not only UNIX but also WIN32 for MinGW
# It's possible to select the exact standard used for compilation.
# It's not necessary, but can be employed for specific purposes.
# Note that zstd source code is compatible with both C++98 and above
# and C-gnu90 (c90 + long long + variadic macros ) and above
# EnableCompilerFlag("-std=c++11" false true) # Set C++ compilation to c++11 standard
# EnableCompilerFlag("-std=c99" true false) # Set C compilation to c99 standard
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
if ((CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") AND MSVC)
# clang-cl normally maps -Wall to -Weverything.
EnableCompilerFlag("/clang:-Wall" _C _CXX false)
EnableCompilerFlag("/clang:-Wall" ${_C} ${_CXX} false)
else ()
EnableCompilerFlag("-Wall" _C _CXX false)
EnableCompilerFlag("-Wall" ${_C} ${_CXX} false)
endif ()
EnableCompilerFlag("-Wextra" _C _CXX false)
EnableCompilerFlag("-Wundef" _C _CXX false)
EnableCompilerFlag("-Wshadow" _C _CXX false)
EnableCompilerFlag("-Wcast-align" _C _CXX false)
EnableCompilerFlag("-Wcast-qual" _C _CXX false)
EnableCompilerFlag("-Wstrict-prototypes" _C false false)
EnableCompilerFlag("-Wextra" ${_C} ${_CXX} false)
EnableCompilerFlag("-Wundef" ${_C} ${_CXX} false)
EnableCompilerFlag("-Wshadow" ${_C} ${_CXX} false)
EnableCompilerFlag("-Wcast-align" ${_C} ${_CXX} false)
EnableCompilerFlag("-Wcast-qual" ${_C} ${_CXX} false)
EnableCompilerFlag("-Wstrict-prototypes" ${_C} false false)
# Enable asserts in Debug mode
if (CMAKE_BUILD_TYPE MATCHES "Debug")
EnableCompilerFlag("-DDEBUGLEVEL=1" _C _CXX false)
EnableCompilerFlag("-DDEBUGLEVEL=1" ${_C} ${_CXX} false)
endif ()
# Add noexecstack flags
# LDFLAGS
EnableCompilerFlag("-Wl,-z,noexecstack" false false _LD)
EnableCompilerFlag("-Wl,-z,noexecstack" false false ${_LD})
# CFLAGS & CXXFLAGS
EnableCompilerFlag("-Qunused-arguments" _C _CXX false)
EnableCompilerFlag("-Wa,--noexecstack" _C _CXX false)
EnableCompilerFlag("-Qunused-arguments" ${_C} ${_CXX} false)
EnableCompilerFlag("-Wa,--noexecstack" ${_C} ${_CXX} false)
# NOTE: Using 3 nested ifs because the variables are sometimes
# empty if the condition is false, and sometimes equal to false.
# This implicitly converts them to truthy values. There may be
# a better way to do this, but this reliably works.
if (${LD_FLAG_WL_Z_NOEXECSTACK})
if (${C_FLAG_WA_NOEXECSTACK})
if (${CXX_FLAG_WA_NOEXECSTACK})
if (LD_FLAG_WL_Z_NOEXECSTACK)
if (C_FLAG_WA_NOEXECSTACK)
if (NOT CMAKE_CXX_COMPILER_LOADED OR CXX_FLAG_WA_NOEXECSTACK)
# We've succeeded in marking the stack as non-executable
set(ZSTD_HAS_NOEXECSTACK true)
endif()
Expand Down
4 changes: 2 additions & 2 deletions build/cmake/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ if (ZSTD_LEGACY_SUPPORT)
${LIBRARY_LEGACY_DIR}/zstd_v07.h)
endif ()

if (MSVC AND NOT (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
if (MSVC AND NOT (CMAKE_C_COMPILER_ID STREQUAL "Clang"))
set(MSVC_RESOURCE_DIR ${ZSTD_SOURCE_DIR}/build/VS2010/libzstd-dll)
set(PlatformDependResources ${MSVC_RESOURCE_DIR}/libzstd-dll.rc)
else()
Expand Down Expand Up @@ -189,7 +189,7 @@ if (MSVC)
endif ()

# With MSVC static library needs to be renamed to avoid conflict with import library
if (MSVC OR (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT MINGW))
if (MSVC OR (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT MINGW))
set(STATIC_LIBRARY_BASE_NAME zstd_static)
else ()
set(STATIC_LIBRARY_BASE_NAME zstd)
Expand Down
3 changes: 2 additions & 1 deletion contrib/linux-kernel/linux_zstd.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,8 @@ typedef ZSTD_Sequence zstd_sequence;
* @in_seqs_size: The number of sequences in in_seqs.
* @literals: The literals associated to the sequences to be compressed.
* @lit_size: The size of the literals in the literals buffer.
* @lit_capacity: The size of the literals buffer.
* @lit_capacity: The size of the literals buffer, which must be at least
* 8 bytes larger than lit_size.
* @decompressed_size: The size of the input data
*
* Return: The compressed size or an error, which can be checked using
Expand Down
79 changes: 79 additions & 0 deletions contrib/seekable_format/tests/seekable_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string.h>

#include "../zstd_seekable.h"
#include "zstd_errors.h"


/* ZSTD_seekable_customFile implementation that reads/seeks a buffer while keeping track of total bytes read */
Expand Down Expand Up @@ -365,6 +366,84 @@ int main(int argc, const char** argv)
}
printf("Success!\n");

printf("Test %u - reject seek table with numFrames beyond format max: ", testNb++);
{ /* A corrupt footer claiming numFrames > ZSTD_SEEKABLE_MAXFRAMES must be
* rejected up front: such a value overflows the seek table size math. */
const uint8_t compressed_data[17] = {
0x5e, 0x2a, 0x4d, 0x18, /* skippable frame magic (| 0xE) */
0x09, 0x00, 0x00, 0x00, /* skippable frame size = 9 */
0x01, 0x00, 0x00, 0x08, /* footer: numFrames = 0x08000001 */
0x00, /* footer: seek table descriptor */
0xb1, 0xea, 0x92, 0x8f, /* seekable magic number */
};

ZSTD_seekable* const stream = ZSTD_seekable_create();
assert(stream != NULL);
{ size_t const status = ZSTD_seekable_initBuff(stream, compressed_data, sizeof(compressed_data));
if (ZSTD_getErrorCode(status) != ZSTD_error_corruption_detected) {
ZSTD_seekable_free(stream);
goto _test_error;
} }
ZSTD_seekable_free(stream);
}
printf("Success!\n");

printf("Test %u - decompress at and past the end of the data: ", testNb++);
{ char const inBuffer[] = "Lorem ipsum dolor sit amet";
size_t const inSize = sizeof(inBuffer);

size_t const seekCapacity = 5000;
void* const seekBuffer = malloc(seekCapacity);
assert(seekBuffer != NULL);
size_t seekSize;

char outBuffer[16];

ZSTD_seekable_CStream* const zscs = ZSTD_seekable_createCStream();
assert(zscs != NULL);
{ size_t const initStatus = ZSTD_seekable_initCStream(zscs, 9, 0 /* checksumFlag */, 0 /* maxFrameSize */);
assert(!ZSTD_isError(initStatus));
}

{ ZSTD_outBuffer outb = { .dst=seekBuffer, .pos=0, .size=seekCapacity };
ZSTD_inBuffer inb = { .src=inBuffer, .pos=0, .size=inSize };

size_t const cStatus = ZSTD_seekable_compressStream(zscs, &outb, &inb);
assert(!ZSTD_isError(cStatus));
assert(inb.pos == inb.size);

size_t const endStatus = ZSTD_seekable_endStream(zscs, &outb);
assert(!ZSTD_isError(endStatus));
seekSize = outb.pos;
}

ZSTD_seekable* const stream = ZSTD_seekable_create();
assert(stream != NULL);
{ size_t const initStatus = ZSTD_seekable_initBuff(stream, seekBuffer, seekSize);
assert(!ZSTD_isError(initStatus)); }

{ size_t const atEnd = ZSTD_seekable_decompress(stream, outBuffer, sizeof(outBuffer), inSize);
size_t const pastEnd = ZSTD_seekable_decompress(stream, outBuffer, sizeof(outBuffer), inSize + 5000);
int failed = atEnd != 0 || !ZSTD_isError(pastEnd);
if (!failed) {
/* offset + len wraps around to 0 */
size_t const wrapped = ZSTD_seekable_decompress(stream, outBuffer, sizeof(outBuffer), 0ULL - sizeof(outBuffer));
failed = !ZSTD_isError(wrapped);
}
if (failed) {
free(seekBuffer);
ZSTD_seekable_freeCStream(zscs);
ZSTD_seekable_free(stream);
goto _test_error;
}
}

free(seekBuffer);
ZSTD_seekable_freeCStream(zscs);
ZSTD_seekable_free(stream);
}
printf("Success!\n");

/* TODO: Add more tests */
printf("Finished tests\n");
return 0;
Expand Down
3 changes: 3 additions & 0 deletions contrib/seekable_format/zstd_seekable.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ ZSTDLIB_API size_t ZSTD_seekable_writeSeekTable(ZSTD_frameLog* fl, ZSTD_outBuffe
* consecutive range of data, it will efficiently retain the decompressor object
* and avoid redecompressing frame prefixes. The return value is the number of
* bytes decompressed, or an error code checkable with ZSTD_isError().
* It is smaller than `dstSize` only when the data ends before
* `offset + dstSize`, and it is 0 when `offset` is the end of the data.
* An `offset` past the end of the data is an error.
*
* The seek table access functions can be used to obtain the data contained
* in the seek table. If frameIndex is larger than the value returned by
Expand Down
12 changes: 10 additions & 2 deletions contrib/seekable_format/zstdseek_decompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,13 @@ static size_t ZSTD_seekable_loadSeekTable(ZSTD_seekable* zs)
U32 const frameSize = tableSize + ZSTD_seekTableFooterSize + ZSTD_SKIPPABLEHEADERSIZE;

U32 remaining = frameSize - ZSTD_seekTableFooterSize; /* don't need to re-read footer */

/* numFrames is bounded by the format (the compressor never writes more
* than ZSTD_SEEKABLE_MAXFRAMES). A larger value can only come from a
* corrupt footer and overflows the tableSize/frameSize math above, so
* reject it before those values are used to seek or size the table. */
if (numFrames > ZSTD_SEEKABLE_MAXFRAMES) return ERROR(corruption_detected);

{ U32 const toRead = MIN(remaining, SEEKABLE_BUFF_SIZE);
CHECK_IO(src.seek(src.opaque, -(S64)frameSize, SEEK_END));
CHECK_IO(src.read(src.opaque, zs->inBuff, toRead));
Expand Down Expand Up @@ -489,8 +496,9 @@ size_t ZSTD_seekable_initAdvanced(ZSTD_seekable* zs, ZSTD_seekable_customFile sr
size_t ZSTD_seekable_decompress(ZSTD_seekable* zs, void* dst, size_t len, unsigned long long offset)
{
unsigned long long const eos = zs->seekTable.entries[zs->seekTable.tableLen].dOffset;
if (offset + len > eos) {
len = eos - offset;
if (offset > eos) return ERROR(parameter_outOfBound);
if (len > eos - offset) {
len = (size_t)(eos - offset);
}

U32 targetFrame = ZSTD_seekable_offsetToFrameIndex(zs, offset);
Expand Down
2 changes: 1 addition & 1 deletion doc/zstd_compression_format.md
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ __`Size_Format`__
- For `Raw_Literals_Block` and `RLE_Literals_Block`,
it's only necessary to decode `Regenerated_Size`.
There is no `Compressed_Size` field.
- For `Compressed_Block` and `Treeless_Literals_Block`,
- For `Compressed_Literals_Block` and `Treeless_Literals_Block`,
it's required to decode both `Compressed_Size`
and `Regenerated_Size` (the decompressed size).
It's also necessary to decode the number of streams (1 or 4).
Expand Down
5 changes: 0 additions & 5 deletions lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,6 @@ The file structure is designed to make this selection manually achievable for an
and assembly decoding loops. You may want to use this macro if these loops are
slower on your platform.

- The macro `ZDICT_QSORT` can enforce selection of a specific sorting variant,
which is useful when autodetection fails, for example with older versions of `musl`.
For this scenario, it can be set as `ZDICT_QSORT=ZDICT_QSORT_C90`.
Other selectable suffixes are `_GNU`, `_APPLE`, `_MSVC` and `_C11`.

#### Windows : using MinGW+MSYS to create DLL

DLL can be created using MinGW+MSYS with the `make libzstd` command.
Expand Down
12 changes: 0 additions & 12 deletions lib/common/zstd_deps.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,6 @@
#ifndef ZSTD_DEPS_COMMON
#define ZSTD_DEPS_COMMON

/* Even though we use qsort_r only for the dictionary builder, the macro
* _GNU_SOURCE has to be declared *before* the inclusion of any standard
* header and the script 'combine.sh' combines the whole zstd source code
* in a single file.
*/
#if defined(__linux) || defined(__linux__) || defined(linux) || defined(__gnu_linux__) || \
defined(__CYGWIN__) || defined(__MSYS__)
#if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */
#define _GNU_SOURCE
#endif
#endif

#include <limits.h>
#include <stddef.h>
#include <string.h>
Expand Down
Loading
Loading