mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-02 08:17:13 +00:00
chore: Do not duplicate sanitizer flags (#7058)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -143,7 +143,6 @@ jobs:
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
SANITIZERS: ${{ inputs.sanitizers }}
|
||||
CMAKE_ARGS: ${{ inputs.cmake_args }}
|
||||
run: |
|
||||
cmake \
|
||||
|
||||
6
BUILD.md
6
BUILD.md
@@ -530,16 +530,16 @@ stored inside the build directory, as either of:
|
||||
## Sanitizers
|
||||
|
||||
To build dependencies and xrpld with sanitizer instrumentation, set the
|
||||
`SANITIZERS` environment variable (only once before running conan and cmake) and use the `sanitizers` profile in conan:
|
||||
`SANITIZERS` environment variable when running `conan install` and use the `sanitizers` profile:
|
||||
|
||||
```bash
|
||||
export SANITIZERS=address,undefinedbehavior
|
||||
|
||||
conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
|
||||
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -Dxrpld=ON -Dtests=ON ..
|
||||
```
|
||||
|
||||
You can then build and test as usual, with the generated `xrpld` binary containing the sanitizer instrumentation. When you run it, it will report any sanitizer errors it detects in the console output.
|
||||
|
||||
See [Sanitizers docs](./docs/build/sanitizers.md) for more details.
|
||||
|
||||
## Options
|
||||
|
||||
@@ -1,140 +1,33 @@
|
||||
#[===================================================================[
|
||||
Configure sanitizers based on environment variables.
|
||||
Apply sanitizer flags built by the Conan profile.
|
||||
|
||||
This module reads the following environment variables:
|
||||
- SANITIZERS: The sanitizers to enable. Possible values:
|
||||
- "address"
|
||||
- "address,undefinedbehavior"
|
||||
- "thread"
|
||||
- "thread,undefinedbehavior"
|
||||
- "undefinedbehavior"
|
||||
Parsing, validation, and flag construction are performed in conan/profiles/sanitizers.
|
||||
This module reads the following CMake variables injected by the Conan toolchain via extra_variables:
|
||||
|
||||
The compiler type and platform are detected in CompilationEnv.cmake.
|
||||
The sanitizer compile options are applied to the 'common' interface library
|
||||
which is linked to all targets in the project.
|
||||
- SANITIZERS: The active sanitizers (e.g. "address,undefinedbehavior").
|
||||
- SANITIZERS_COMPILER_FLAGS: Space-separated compiler flags.
|
||||
- SANITIZERS_LINKER_FLAGS: Space-separated linker flags.
|
||||
|
||||
Internal flag variables set by this module:
|
||||
|
||||
- SANITIZER_TYPES: List of sanitizer types to enable (e.g., "address",
|
||||
"thread", "undefined"). And two more flags for undefined behavior sanitizer (e.g., "float-divide-by-zero", "unsigned-integer-overflow").
|
||||
This list is joined with commas and passed to -fsanitize=<list>.
|
||||
|
||||
- SANITIZERS_COMPILE_FLAGS: Compiler flags for sanitizer instrumentation.
|
||||
Includes:
|
||||
* -fno-omit-frame-pointer: Preserves frame pointers for stack traces
|
||||
* -O1: Minimum optimization for reasonable performance
|
||||
* -fsanitize=<types>: Enables sanitizer instrumentation
|
||||
* -fsanitize-ignorelist=<path>: (Clang only) Compile-time ignorelist
|
||||
* -mcmodel=large/medium: (GCC only) Code model for large binaries
|
||||
* -Wno-stringop-overflow: (GCC only) Suppresses false positive warnings
|
||||
* -Wno-tsan: (For GCC TSAN combination only) Suppresses atomic_thread_fence warnings
|
||||
|
||||
- SANITIZERS_LINK_FLAGS: Linker flags for sanitizer runtime libraries.
|
||||
Includes:
|
||||
* -fsanitize=<types>: Links sanitizer runtime libraries
|
||||
* -mcmodel=large/medium: (GCC only) Matches compile-time code model
|
||||
|
||||
- SANITIZERS_RELOCATION_FLAGS: (GCC only, x86_64 only) Code model flags for linking.
|
||||
Used to handle large instrumented binaries on x86_64:
|
||||
* -mcmodel=large: For AddressSanitizer (prevents relocation errors)
|
||||
* -mcmodel=medium: For ThreadSanitizer (large model is incompatible)
|
||||
On ARM64, these flags are omitted since GCC does not support
|
||||
-mcmodel=large with -fPIC, and -mcmodel=medium does not exist.
|
||||
The flags are applied to the 'common' interface library which is linked to all targets in the project.
|
||||
#]===================================================================]
|
||||
|
||||
include_guard(GLOBAL)
|
||||
include(CompilationEnv)
|
||||
|
||||
# Read environment variable
|
||||
set(SANITIZERS "")
|
||||
if(DEFINED ENV{SANITIZERS})
|
||||
set(SANITIZERS "$ENV{SANITIZERS}")
|
||||
endif()
|
||||
|
||||
# Set SANITIZERS_ENABLED flag for use in other modules
|
||||
if(SANITIZERS MATCHES "address|thread|undefinedbehavior")
|
||||
set(SANITIZERS_ENABLED TRUE)
|
||||
else()
|
||||
if(NOT DEFINED SANITIZERS)
|
||||
set(SANITIZERS_ENABLED FALSE)
|
||||
return()
|
||||
endif()
|
||||
set(SANITIZERS_ENABLED TRUE)
|
||||
|
||||
# Sanitizers are not supported on Windows/MSVC
|
||||
if(is_msvc)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Sanitizers are not supported on Windows/MSVC. "
|
||||
"Please unset the SANITIZERS environment variable."
|
||||
)
|
||||
endif()
|
||||
message(STATUS "=== Configuring Sanitizers ===")
|
||||
message(STATUS " SANITIZERS: ${SANITIZERS}")
|
||||
message(STATUS " Compile flags: ${SANITIZERS_COMPILER_FLAGS}")
|
||||
message(STATUS " Link flags: ${SANITIZERS_LINKER_FLAGS}")
|
||||
|
||||
message(STATUS "Configuring sanitizers: ${SANITIZERS}")
|
||||
|
||||
# Parse SANITIZERS value to determine which sanitizers to enable
|
||||
set(enable_asan FALSE)
|
||||
set(enable_tsan FALSE)
|
||||
set(enable_ubsan FALSE)
|
||||
|
||||
# Normalize SANITIZERS into a list
|
||||
set(san_list "${SANITIZERS}")
|
||||
string(REPLACE "," ";" san_list "${san_list}")
|
||||
separate_arguments(san_list)
|
||||
|
||||
foreach(san IN LISTS san_list)
|
||||
if(san STREQUAL "address")
|
||||
set(enable_asan TRUE)
|
||||
elseif(san STREQUAL "thread")
|
||||
set(enable_tsan TRUE)
|
||||
elseif(san STREQUAL "undefinedbehavior")
|
||||
set(enable_ubsan TRUE)
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unsupported sanitizer type: ${san}"
|
||||
"Supported: address, thread, undefinedbehavior and their combinations."
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Validate sanitizer compatibility
|
||||
if(enable_asan AND enable_tsan)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously. "
|
||||
"Use 'address' or 'thread', optionally with 'undefinedbehavior'."
|
||||
)
|
||||
endif()
|
||||
|
||||
# Frame pointer is required for meaningful stack traces. Sanitizers recommend minimum of -O1 for reasonable performance
|
||||
set(SANITIZERS_COMPILE_FLAGS "-fno-omit-frame-pointer" "-O1")
|
||||
|
||||
# Build the sanitizer flags list
|
||||
set(SANITIZER_TYPES)
|
||||
|
||||
if(enable_asan)
|
||||
list(APPEND SANITIZER_TYPES "address")
|
||||
elseif(enable_tsan)
|
||||
list(APPEND SANITIZER_TYPES "thread")
|
||||
endif()
|
||||
|
||||
if(enable_ubsan)
|
||||
# UB sanitizer flags
|
||||
list(APPEND SANITIZER_TYPES "undefined" "float-divide-by-zero")
|
||||
if(is_clang)
|
||||
# Clang supports additional UB checks. More info here
|
||||
# https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
|
||||
list(APPEND SANITIZER_TYPES "unsigned-integer-overflow")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Configure code model for GCC on amd64 Use large code model for ASAN to avoid relocation errors Use medium code model
|
||||
# for TSAN (large is not compatible with TSAN)
|
||||
set(SANITIZERS_RELOCATION_FLAGS)
|
||||
|
||||
# Compiler-specific configuration
|
||||
# GCC with sanitizers is incompatible with mold, gold, and lld linkers.
|
||||
# Namely, the instrumented binary exceeds size limits imposed by these linkers.
|
||||
if(is_gcc)
|
||||
# Disable mold, gold and lld linkers for GCC with sanitizers Use default linker (bfd/ld) which is more lenient with
|
||||
# mixed code models This is needed since the size of instrumented binary exceeds the limits set by mold, lld and
|
||||
# gold linkers
|
||||
set(use_mold OFF CACHE BOOL "Use mold linker" FORCE)
|
||||
set(use_gold OFF CACHE BOOL "Use gold linker" FORCE)
|
||||
set(use_lld OFF CACHE BOOL "Use lld linker" FORCE)
|
||||
@@ -142,82 +35,62 @@ if(is_gcc)
|
||||
STATUS
|
||||
" Disabled mold, gold, and lld linkers for GCC with sanitizers"
|
||||
)
|
||||
|
||||
# Suppress false positive warnings in GCC with stringop-overflow
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-stringop-overflow")
|
||||
|
||||
if(is_amd64 AND enable_asan)
|
||||
message(STATUS " Using large code model (-mcmodel=large)")
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=large")
|
||||
list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=large")
|
||||
elseif(enable_tsan)
|
||||
# GCC doesn't support atomic_thread_fence with tsan. Suppress warnings.
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-tsan")
|
||||
if(is_amd64)
|
||||
message(STATUS " Using medium code model (-mcmodel=medium)")
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=medium")
|
||||
list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=medium")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Join sanitizer flags with commas for -fsanitize option
|
||||
list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR)
|
||||
|
||||
# Add sanitizer to compile and link flags
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
|
||||
set(SANITIZERS_LINK_FLAGS
|
||||
"${SANITIZERS_RELOCATION_FLAGS}"
|
||||
"-fsanitize=${SANITIZER_TYPES_STR}"
|
||||
)
|
||||
elseif(is_clang)
|
||||
# Add ignorelist for Clang (GCC doesn't support this) Use CMAKE_SOURCE_DIR to get the path to the ignorelist
|
||||
set(IGNORELIST_PATH
|
||||
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
|
||||
)
|
||||
if(NOT EXISTS "${IGNORELIST_PATH}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Sanitizer ignorelist not found: ${IGNORELIST_PATH}"
|
||||
)
|
||||
endif()
|
||||
|
||||
list(
|
||||
APPEND SANITIZERS_COMPILE_FLAGS
|
||||
"-fsanitize-ignorelist=${IGNORELIST_PATH}"
|
||||
)
|
||||
message(STATUS " Using sanitizer ignorelist: ${IGNORELIST_PATH}")
|
||||
|
||||
# Join sanitizer flags with commas for -fsanitize option
|
||||
list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR)
|
||||
|
||||
# Add sanitizer to compile and link flags
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
|
||||
set(SANITIZERS_LINK_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
|
||||
endif()
|
||||
|
||||
message(STATUS " Compile flags: ${SANITIZERS_COMPILE_FLAGS}")
|
||||
message(STATUS " Link flags: ${SANITIZERS_LINK_FLAGS}")
|
||||
# Flags arrive as space-separated strings; split into CMake lists before use
|
||||
separate_arguments(
|
||||
sanitizers_compiler_flags
|
||||
UNIX_COMMAND
|
||||
"${SANITIZERS_COMPILER_FLAGS}"
|
||||
)
|
||||
separate_arguments(
|
||||
sanitizers_linker_flags
|
||||
UNIX_COMMAND
|
||||
"${SANITIZERS_LINKER_FLAGS}"
|
||||
)
|
||||
|
||||
# Apply the sanitizer flags to the 'common' interface library This is the same library used by XrplCompiler.cmake
|
||||
target_compile_options(
|
||||
common
|
||||
INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:${SANITIZERS_COMPILE_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${SANITIZERS_COMPILE_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:${sanitizers_compiler_flags}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${sanitizers_compiler_flags}>
|
||||
)
|
||||
target_link_options(common INTERFACE ${sanitizers_linker_flags})
|
||||
|
||||
# Apply linker flags
|
||||
target_link_options(common INTERFACE ${SANITIZERS_LINK_FLAGS})
|
||||
# This module appends -fsanitize-ignorelist=<path> for Clang builds.
|
||||
# The ignorelist path contains CMAKE_SOURCE_DIR, so it must be set here, rather than in the Conan profile.
|
||||
# GCC does not support -fsanitize-ignorelist.
|
||||
if(is_clang)
|
||||
set(ignorelist_path
|
||||
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
|
||||
)
|
||||
if(NOT EXISTS "${ignorelist_path}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Sanitizer ignorelist not found: ${ignorelist_path}"
|
||||
)
|
||||
endif()
|
||||
target_compile_options(
|
||||
common
|
||||
INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fsanitize-ignorelist=${ignorelist_path}>
|
||||
$<$<COMPILE_LANGUAGE:C>:-fsanitize-ignorelist=${ignorelist_path}>
|
||||
)
|
||||
message(STATUS " Ignorelist: ${ignorelist_path}")
|
||||
endif()
|
||||
|
||||
# Define SANITIZERS macro for BuildInfo.cpp
|
||||
set(sanitizers_list)
|
||||
if(enable_asan)
|
||||
if(SANITIZERS MATCHES "address")
|
||||
set(enable_asan ON)
|
||||
list(APPEND sanitizers_list "ASAN")
|
||||
endif()
|
||||
if(enable_tsan)
|
||||
if(SANITIZERS MATCHES "thread")
|
||||
set(enable_tsan ON)
|
||||
list(APPEND sanitizers_list "TSAN")
|
||||
endif()
|
||||
if(enable_ubsan)
|
||||
if(SANITIZERS MATCHES "undefinedbehavior")
|
||||
set(enable_ubsan ON)
|
||||
list(APPEND sanitizers_list "UBSAN")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
include(sanitizers)
|
||||
include(sanitizers)
|
||||
|
||||
@@ -3,96 +3,120 @@ include(default)
|
||||
{% set arch = detect_api.detect_arch() %}
|
||||
{% set sanitizers = os.getenv("SANITIZERS") %}
|
||||
|
||||
[conf]
|
||||
{% if sanitizers %}
|
||||
{% if compiler == "gcc" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set model_code = "" %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %}
|
||||
{% if not sanitizers %}
|
||||
{# Sanitizers not configured; no additional settings needed #}
|
||||
{% else %}
|
||||
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% if arch == "x86_64" %}
|
||||
{% set model_code = "-mcmodel=large" %}
|
||||
{% endif %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% if arch == "x86_64" %}
|
||||
{% set model_code = "-mcmodel=medium" %}
|
||||
{% endif %}
|
||||
{% set _ = extra_cxxflags.append("-Wno-tsan") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
{% if compiler == "msvc" %}
|
||||
{{ "Sanitizers are not supported on Windows/MSVC. Please unset the SANITIZERS environment variable." }}
|
||||
{% endif %}
|
||||
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("undefined") %}
|
||||
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
|
||||
{% endif %}
|
||||
{% set known_sanitizers = ["address", "thread", "undefinedbehavior"] %}
|
||||
{% set provided_sanitizers = [] %}
|
||||
{% for san in sanitizers.split(",") %}
|
||||
{% set san = san.strip() %}
|
||||
{% if san not in known_sanitizers %}
|
||||
{{ "Unknown sanitizer in SANITIZERS: " ~ san }}
|
||||
{% endif %}
|
||||
{% set _ = provided_sanitizers.append(san) %}
|
||||
{% endfor %}
|
||||
|
||||
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) ~ " " ~ model_code %}
|
||||
{% set enable_asan = "address" in provided_sanitizers %}
|
||||
{% set enable_tsan = "thread" in provided_sanitizers %}
|
||||
{% set enable_ubsan = "undefinedbehavior" in provided_sanitizers %}
|
||||
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% elif compiler == "apple-clang" or compiler == "clang" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %}
|
||||
{% if enable_asan and enable_tsan %}
|
||||
{{ "AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously." }}
|
||||
{% endif %}
|
||||
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
{% set sanitizer_types = [] %}
|
||||
{% set defines = [] %}
|
||||
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("undefined") %}
|
||||
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
|
||||
{% set _ = sanitizer_list.append("unsigned-integer-overflow") %}
|
||||
{% endif %}
|
||||
{% if enable_asan %}
|
||||
{% set _ = sanitizer_types.append("address") %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN") %}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT") %}
|
||||
{% elif enable_tsan %}
|
||||
{% set _ = sanitizer_types.append("thread") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN") %}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT") %}
|
||||
{% endif %}
|
||||
|
||||
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) %}
|
||||
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% if enable_ubsan %}
|
||||
{% set _ = sanitizer_types.append("undefined") %}
|
||||
{% set _ = sanitizer_types.append("float-divide-by-zero") %}
|
||||
{# Clang supports additional UB checks beyond the GCC baseline #}
|
||||
{% if compiler == "clang" or compiler == "apple-clang" %}
|
||||
{% set _ = sanitizer_types.append("unsigned-integer-overflow") %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# Frame pointer required for meaningful stack traces; -O1 for reasonable performance #}
|
||||
{% set compile_flags = ["-fno-omit-frame-pointer", "-O1"] %}
|
||||
|
||||
{% if compiler == "gcc" %}
|
||||
{# Suppress false positive warnings with GCC #}
|
||||
{% set _ = compile_flags.append("-Wno-stringop-overflow") %}
|
||||
|
||||
{% set relocation_flags = [] %}
|
||||
|
||||
{% if arch == "x86_64" and enable_asan %}
|
||||
{# Large code model prevents relocation errors in instrumented ASAN binaries #}
|
||||
{% set _ = compile_flags.append("-mcmodel=large") %}
|
||||
{% set _ = relocation_flags.append("-mcmodel=large") %}
|
||||
{% elif enable_tsan %}
|
||||
{# GCC doesn't support atomic_thread_fence with TSAN; suppress warnings #}
|
||||
{% set _ = compile_flags.append("-Wno-tsan") %}
|
||||
{% if arch == "x86_64" %}
|
||||
{# Medium code model for TSAN; large is incompatible #}
|
||||
{% set _ = compile_flags.append("-mcmodel=medium") %}
|
||||
{% set _ = relocation_flags.append("-mcmodel=medium") %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% set fsanitize = "-fsanitize=" ~ ",".join(sanitizer_types) %}
|
||||
{% set _ = compile_flags.append(fsanitize) %}
|
||||
{% set _ = relocation_flags.append(fsanitize) %}
|
||||
|
||||
{% set sanitizer_compiler_flags = " ".join(compile_flags) %}
|
||||
{% set sanitizer_linker_flags = " ".join(relocation_flags) %}
|
||||
{% elif compiler == "clang" or compiler == "apple-clang" %}
|
||||
{% set fsanitize = "-fsanitize=" ~ ",".join(sanitizer_types) %}
|
||||
{% set _ = compile_flags.append(fsanitize) %}
|
||||
|
||||
{% set sanitizer_compiler_flags = " ".join(compile_flags) %}
|
||||
{% set sanitizer_linker_flags = fsanitize %}
|
||||
{% endif %}
|
||||
|
||||
[conf]
|
||||
tools.build:defines+={{defines}}
|
||||
tools.build:cxxflags+=['{{sanitizer_compiler_flags}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_linker_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_linker_flags}}']
|
||||
|
||||
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"]
|
||||
|
||||
# &: means "apply only to the consumer/root package"
|
||||
&:tools.cmake.cmaketoolchain:extra_variables={"SANITIZERS": "{{sanitizers}}", "SANITIZERS_COMPILER_FLAGS": "{{sanitizer_compiler_flags}}", "SANITIZERS_LINKER_FLAGS": "{{sanitizer_linker_flags}}"}
|
||||
|
||||
[options]
|
||||
{% if sanitizers %}
|
||||
{% if "address" in sanitizers %}
|
||||
# Build Boost.Context with ucontext backend (not fcontext) so that
|
||||
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
|
||||
# are compiled into the library. fcontext (assembly) has no ASAN support.
|
||||
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
|
||||
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
|
||||
boost/*:without_context=False
|
||||
# Boost stacktrace fails to build with some sanitizers
|
||||
boost/*:without_stacktrace=True
|
||||
{% elif "thread" in sanitizers %}
|
||||
# Build Boost.Context with ucontext backend for TSAN. fcontext (assembly)
|
||||
# has no TSAN annotations, so without this the BOOST_USE_TSAN/BOOST_USE_UCONTEXT
|
||||
# defines in [conf] would be ineffective.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext thread-sanitizer=on define=BOOST_USE_TSAN=1
|
||||
boost/*:without_context=False
|
||||
boost/*:without_stacktrace=True
|
||||
{% endif %}
|
||||
{% if enable_asan %}
|
||||
# Build Boost.Context with ucontext backend (not fcontext) so that
|
||||
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
|
||||
# are compiled into the library. fcontext (assembly) has no ASAN support.
|
||||
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
|
||||
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
|
||||
boost/*:without_context=False
|
||||
# Boost stacktrace fails to build with some sanitizers
|
||||
boost/*:without_stacktrace=True
|
||||
{% elif enable_tsan %}
|
||||
# Build Boost.Context with ucontext backend for TSAN. fcontext (assembly)
|
||||
# has no TSAN annotations, so without this the BOOST_USE_TSAN/BOOST_USE_UCONTEXT
|
||||
# defines in [conf] would be ineffective.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext thread-sanitizer=on define=BOOST_USE_TSAN=1
|
||||
boost/*:without_context=False
|
||||
boost/*:without_stacktrace=True
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
@@ -71,6 +71,7 @@ words:
|
||||
- citardauq
|
||||
- clawback
|
||||
- clawbacks
|
||||
- cmaketoolchain
|
||||
- coeffs
|
||||
- coldwallet
|
||||
- compr
|
||||
|
||||
45
docs/build/sanitizers.md
vendored
45
docs/build/sanitizers.md
vendored
@@ -1,15 +1,17 @@
|
||||
# Sanitizer Configuration for Xrpld
|
||||
|
||||
This document explains how to properly configure and run sanitizers (AddressSanitizer, undefinedbehaviorSanitizer, ThreadSanitizer) with the xrpld project.
|
||||
This document explains how to properly configure and run sanitizers (`AddressSanitizer`, `UndefinedBehaviorSanitizer`, `ThreadSanitizer`) with the xrpld project.
|
||||
Corresponding suppression files are located in the `sanitizers/suppressions` directory.
|
||||
|
||||
> [!CAUTION]
|
||||
> Do not mix Address and Thread sanitizers - they are incompatible.
|
||||
> Also, we don't yet support MSVC sanitizers, so this is only for Clang/GCC builds.
|
||||
|
||||
- [Sanitizer Configuration for Xrpld](#sanitizer-configuration-for-xrpld)
|
||||
- [Building with Sanitizers](#building-with-sanitizers)
|
||||
- [Summary](#summary)
|
||||
- [Build steps:](#build-steps)
|
||||
- [Install dependencies](#install-dependencies)
|
||||
- [Call CMake](#call-cmake)
|
||||
- [Build](#build)
|
||||
- [Running Tests with Sanitizers](#running-tests-with-sanitizers)
|
||||
- [AddressSanitizer (ASAN)](#addresssanitizer-asan)
|
||||
- [ThreadSanitizer (TSan)](#threadsanitizer-tsan)
|
||||
@@ -33,9 +35,13 @@ Corresponding suppression files are located in the `sanitizers/suppressions` dir
|
||||
Follow the same instructions as mentioned in [BUILD.md](../../BUILD.md) but with the following changes:
|
||||
|
||||
1. Make sure you have a clean build directory.
|
||||
2. Set the `SANITIZERS` environment variable before calling conan install and cmake. Only set it once. Make sure both conan and cmake read the same values.
|
||||
2. Set the `SANITIZERS` environment variable before calling `conan install`. Only set it once.
|
||||
Example: `export SANITIZERS=address,undefinedbehavior`
|
||||
3. Optionally use `--profile:all sanitizers` with Conan to build dependencies with sanitizer instrumentation. [!NOTE]Building with sanitizer-instrumented dependencies is slower but produces fewer false positives.
|
||||
3. Use `--profile:all sanitizers` with Conan to build dependencies with sanitizer instrumentation.
|
||||
|
||||
> [!NOTE]
|
||||
> Building with sanitizer-instrumented dependencies is slower but produces fewer false positives.
|
||||
|
||||
4. Set `ASAN_OPTIONS`, `LSAN_OPTIONS`, `UBSAN_OPTIONS` and `TSAN_OPTIONS` environment variables to configure sanitizer behavior when running executables. [More details below](#running-tests-with-sanitizers).
|
||||
|
||||
---
|
||||
@@ -51,36 +57,13 @@ cd .build
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
The `SANITIZERS` environment variable is used by both Conan and CMake.
|
||||
The `SANITIZERS` environment variable is used during `conan install` command.
|
||||
|
||||
```bash
|
||||
export SANITIZERS=address,undefinedbehavior
|
||||
# Standard build (without instrumenting dependencies)
|
||||
conan install .. --output-folder . --build missing --settings build_type=Debug
|
||||
|
||||
# Or with sanitizer-instrumented dependencies (takes longer but fewer false positives)
|
||||
conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
|
||||
SANITIZERS=address,undefinedbehavior conan install .. --output-folder . --build missing --settings build_type=Debug --profile:all sanitizers
|
||||
```
|
||||
|
||||
[!CAUTION]
|
||||
Do not mix Address and Thread sanitizers - they are incompatible.
|
||||
|
||||
Since you already set the `SANITIZERS` environment variable when running Conan, same values will be read for the next part.
|
||||
|
||||
#### Call CMake
|
||||
|
||||
```bash
|
||||
cmake .. -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-Dtests=ON -Dxrpld=ON
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
```bash
|
||||
cmake --build . --parallel 4
|
||||
```
|
||||
Proceed with the rest of the build instructions as mentioned in [BUILD.md](../../BUILD.md).
|
||||
|
||||
## Running Tests with Sanitizers
|
||||
|
||||
|
||||
Reference in New Issue
Block a user