Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions build/cmake/CMakeModules/ZstdOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,13 @@ endif()

# Set global definitions
add_definitions(-DXXH_NAMESPACE=ZSTD_)

# Optional experimental Clang -fbounds-safety (OFF by default; macros inert otherwise)
option(ZSTD_ENABLE_FBOUNDS_SAFETY
"Enable experimental Clang -fbounds-safety annotations (OFF by default)"
OFF)
if(ZSTD_ENABLE_FBOUNDS_SAFETY)
message(STATUS "ZSTD_ENABLE_FBOUNDS_SAFETY enabled")
else()
message(STATUS "ZSTD_ENABLE_FBOUNDS_SAFETY disabled")
endif()
10 changes: 10 additions & 0 deletions build/cmake/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,16 @@ configure_file("${LIBRARY_DIR}/libzstd.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libzs
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libzstd.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")

# install target
# Optional -fbounds-safety (inert macros unless enabled)
if(ZSTD_ENABLE_FBOUNDS_SAFETY)
foreach(_zstd_tgt IN ITEMS libzstd_shared libzstd_static)
if(TARGET ${_zstd_tgt})
target_compile_definitions(${_zstd_tgt} PUBLIC ZSTD_SUPPORT_FBOUNDS_SAFETY)
target_compile_options(${_zstd_tgt} PUBLIC -fbounds-safety)
endif()
endforeach()
endif()

install(FILES ${PublicHeaders} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")

foreach(target_suffix IN ITEMS "_shared" "_static" "")
Expand Down
2 changes: 2 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ install-includes:
[ -e $(DESTDIR)$(INCLUDEDIR) ] || $(INSTALL) -d -m 755 $(DESTDIR)$(INCLUDEDIR)/
@echo Installing includes
$(INSTALL_DATA) zstd.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) zstd_bounds_safety.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) zstd_errors.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_DATA) zdict.h $(DESTDIR)$(INCLUDEDIR)

Expand All @@ -382,6 +383,7 @@ uninstall:
$(RM) $(DESTDIR)$(LIBDIR)/$(LIBZSTD)
$(RM) $(DESTDIR)$(PKGCONFIGDIR)/libzstd.pc
$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd.h
$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_bounds_safety.h
$(RM) $(DESTDIR)$(INCLUDEDIR)/zstd_errors.h
$(RM) $(DESTDIR)$(INCLUDEDIR)/zdict.h
@echo zstd libraries successfully uninstalled
Expand Down
5 changes: 3 additions & 2 deletions lib/decompress/zstd_decompress.c
Original file line number Diff line number Diff line change
Expand Up @@ -2394,11 +2394,12 @@ size_t ZSTD_decompressStream_simpleArgs (
{
ZSTD_outBuffer output;
ZSTD_inBuffer input;
output.dst = dst;
/* Capacity before pointer so sized_by invariants hold under -fbounds-safety. */
output.size = dstCapacity;
output.dst = dst;
output.pos = *dstPos;
input.src = src;
input.size = srcSize;
input.src = src;
input.pos = *srcPos;
{ size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
*dstPos = output.pos;
Expand Down
7 changes: 7 additions & 0 deletions lib/libzstd.mk
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ endif
# Assembly support
ZSTD_NO_ASM ?= 0

# Optional Clang -fbounds-safety (OFF by default; inert macros otherwise)
ENABLE_FBOUNDS_SAFETY ?= 0
ifeq ($(ENABLE_FBOUNDS_SAFETY),1)
CPPFLAGS += -DZSTD_SUPPORT_FBOUNDS_SAFETY
CFLAGS += -fbounds-safety
endif

ZSTD_LIB_EXCLUDE_COMPRESSORS_DFAST_AND_UP ?= 0
ZSTD_LIB_EXCLUDE_COMPRESSORS_GREEDY_AND_UP ?= 0

Expand Down
13 changes: 11 additions & 2 deletions lib/zstd.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <stddef.h> /* size_t */

#include "zstd_errors.h" /* list of errors */
#include "zstd_bounds_safety.h" /* optional -fbounds-safety macros */
#if defined(ZSTD_STATIC_LINKING_ONLY) && !defined(ZSTD_H_ZSTD_STATIC_LINKING_ONLY)
#include <limits.h> /* INT_MAX */
#endif /* ZSTD_STATIC_LINKING_ONLY */
Expand Down Expand Up @@ -699,13 +700,21 @@ ZSTDLIB_API size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset);
****************************/

typedef struct ZSTD_inBuffer_s {
const void* src; /**< start of input buffer */
/* size is the capacity companion for src (bytes).
* Field order is preserved (pointer before size) for public ABI;
* update sites assign capacity before the pointer so sized-by
* invariants hold under optional -fbounds-safety builds.
*/
const void* ZSTD_SIZED_BY_OR_NULL(size) src; /**< start of input buffer */
size_t size; /**< size of input buffer */
size_t pos; /**< position where reading stopped. Will be updated. Necessarily 0 <= pos <= size */
} ZSTD_inBuffer;

typedef struct ZSTD_outBuffer_s {
void* dst; /**< start of output buffer */
/* size is the capacity companion for dst (bytes). Same ABI /
* capacity-first assignment notes as ZSTD_inBuffer.
*/
void* ZSTD_SIZED_BY_OR_NULL(size) dst; /**< start of output buffer */
size_t size; /**< size of output buffer */
size_t pos; /**< position where writing stopped. Will be updated. Necessarily 0 <= pos <= size */
} ZSTD_outBuffer;
Expand Down
44 changes: 44 additions & 0 deletions lib/zstd_bounds_safety.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* zstd_bounds_safety.h - portability macros for optional -fbounds-safety
*
* Copyright (c) 2026 Jeff Bindel <jeff@incrediblybased.co>
*
* 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.
*
* When ZSTD_SUPPORT_FBOUNDS_SAFETY is defined (typically via
* -DZSTD_SUPPORT_FBOUNDS_SAFETY and a Clang toolchain that implements
* -fbounds-safety), these macros expand to Clang bounds annotations.
* Otherwise they expand to nothing so default builds are unchanged.
*
* Pattern matches libwebp / libpng / giflib / lz4 inert-macro
* -fbounds-safety adoption: annotations are inert unless explicitly enabled.
*/
#ifndef ZSTD_BOUNDS_SAFETY_H_235446
#define ZSTD_BOUNDS_SAFETY_H_235446

#ifdef ZSTD_SUPPORT_FBOUNDS_SAFETY

# include <ptrcheck.h>
/* Non-ABI-breaking sized-by annotations for byte buffers whose companion
* field / argument is a capacity in bytes (ZSTD_inBuffer.size /
* ZSTD_outBuffer.size). Use *_OR_NULL when the pointer may be NULL while
* the companion size is zero.
*/
# define ZSTD_SIZED_BY(n) __sized_by(n)
# define ZSTD_SIZED_BY_OR_NULL(n) __sized_by_or_null(n)
# define ZSTD_COUNTED_BY(n) __counted_by(n)
# define ZSTD_COUNTED_BY_OR_NULL(n) __counted_by_or_null(n)

#else /* !ZSTD_SUPPORT_FBOUNDS_SAFETY */

# define ZSTD_SIZED_BY(n)
# define ZSTD_SIZED_BY_OR_NULL(n)
# define ZSTD_COUNTED_BY(n)
# define ZSTD_COUNTED_BY_OR_NULL(n)

#endif /* ZSTD_SUPPORT_FBOUNDS_SAFETY */

#endif /* ZSTD_BOUNDS_SAFETY_H_235446 */