mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-01 16:35:53 +00:00
Compare commits
157 Commits
vlntb/mall
...
pratik/Add
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f09fbe807 | ||
|
|
734f8a9810 | ||
|
|
935e45bcca | ||
|
|
0b612b5c13 | ||
|
|
7617072ebc | ||
|
|
4a61ff3bef | ||
|
|
7097566d9d | ||
|
|
afedb276db | ||
|
|
941775fec4 | ||
|
|
4058ca01ac | ||
|
|
9c5df200b8 | ||
|
|
96e8ee4bdd | ||
|
|
c182d13ab5 | ||
|
|
d942fd9f9c | ||
|
|
064d51b79c | ||
|
|
6202148623 | ||
|
|
954fe68e91 | ||
|
|
1d38504d85 | ||
|
|
9cdabe98e2 | ||
|
|
49f8daf82f | ||
|
|
dd9e554d4a | ||
|
|
facb6c63e3 | ||
|
|
32d129ee5e | ||
|
|
6e32392f93 | ||
|
|
39ace64833 | ||
|
|
4430cb64b8 | ||
|
|
d4b033958e | ||
|
|
1a08b97fb6 | ||
|
|
6407788b0f | ||
|
|
702d94134e | ||
|
|
7d3fc5c396 | ||
|
|
810f5e94db | ||
|
|
d026d0640f | ||
|
|
5befd5d249 | ||
|
|
4f496db291 | ||
|
|
10553fc437 | ||
|
|
087e52ea36 | ||
|
|
cb982e7a8a | ||
|
|
2610e653d6 | ||
|
|
b6c313bb94 | ||
|
|
a3e42a0d11 | ||
|
|
92a6c986b3 | ||
|
|
dd0408ac53 | ||
|
|
0fcfcd059e | ||
|
|
4c0f7a337a | ||
|
|
640f9ff5e2 | ||
|
|
42cab6c826 | ||
|
|
9267756944 | ||
|
|
3b1e82b412 | ||
|
|
7d7c659822 | ||
|
|
a58df41a4d | ||
|
|
d01b1da80e | ||
|
|
216ecf67e1 | ||
|
|
d8c8900fbb | ||
|
|
e2c75f5d60 | ||
|
|
2428c5c196 | ||
|
|
d8ff72b342 | ||
|
|
4fc5c00c24 | ||
|
|
5a9014912c | ||
|
|
8006a1e967 | ||
|
|
6610f469df | ||
|
|
9f026929cf | ||
|
|
a9d134af85 | ||
|
|
18b9b9da19 | ||
|
|
6a89a544fe | ||
|
|
427771775e | ||
|
|
67946f4993 | ||
|
|
8d8a0cb970 | ||
|
|
89f9ede1f5 | ||
|
|
aac1076d83 | ||
|
|
c0da02814b | ||
|
|
013ff18fce | ||
|
|
e1403d56ef | ||
|
|
58b248d9a4 | ||
|
|
f1561c5b48 | ||
|
|
73ab466029 | ||
|
|
4cf4802971 | ||
|
|
8d6d2ec455 | ||
|
|
4248a1fbb6 | ||
|
|
7edba0a856 | ||
|
|
b38ef53c44 | ||
|
|
baee65bd28 | ||
|
|
2e53c5ab80 | ||
|
|
09a6e46c39 | ||
|
|
a93052e765 | ||
|
|
1cc00cddd8 | ||
|
|
5f2a351e3f | ||
|
|
5e89bce8d9 | ||
|
|
9b793cd429 | ||
|
|
b650852fa7 | ||
|
|
1d76de83f6 | ||
|
|
ea4d062e68 | ||
|
|
dcd0553050 | ||
|
|
6355eba88e | ||
|
|
2e5afa7556 | ||
|
|
7d05090d68 | ||
|
|
916f00039c | ||
|
|
e687ab8653 | ||
|
|
b182b6abf7 | ||
|
|
509d388f97 | ||
|
|
fd712770e1 | ||
|
|
695f4a2cc9 | ||
|
|
5ea3b4327d | ||
|
|
a9444d3a42 | ||
|
|
20326a785b | ||
|
|
5ef2ced584 | ||
|
|
a011d29fcb | ||
|
|
9abec17536 | ||
|
|
2bc089a962 | ||
|
|
14f605b2f9 | ||
|
|
f2365543fb | ||
|
|
d9c26bd7a9 | ||
|
|
937dc8740e | ||
|
|
9b92aafe6d | ||
|
|
124b6ca4bd | ||
|
|
28885a4638 | ||
|
|
5478e4fee6 | ||
|
|
72b3a03538 | ||
|
|
18b65fd129 | ||
|
|
ebf917ab15 | ||
|
|
2178fb919f | ||
|
|
e156ed40ba | ||
|
|
db5aa2d277 | ||
|
|
e347da9fac | ||
|
|
6b8d5b57e1 | ||
|
|
0029210926 | ||
|
|
832c32d15c | ||
|
|
39adc5a82b | ||
|
|
1f88697f54 | ||
|
|
4a0fc0f686 | ||
|
|
f5b473ccd1 | ||
|
|
71212677c0 | ||
|
|
abfaac5c64 | ||
|
|
cb5a76589e | ||
|
|
d077141d75 | ||
|
|
1eb3cc4ec7 | ||
|
|
34b10b87e6 | ||
|
|
c0ecb9a0cd | ||
|
|
c15d6399fb | ||
|
|
0b1bd42cc0 | ||
|
|
30f7ef7676 | ||
|
|
e7da05e44c | ||
|
|
1cdd0bf63e | ||
|
|
48a3e5ea31 | ||
|
|
10a422dd69 | ||
|
|
b150feaab6 | ||
|
|
ada523071f | ||
|
|
ff0284e984 | ||
|
|
0be98ac610 | ||
|
|
83eb93f5d7 | ||
|
|
db74cebc8b | ||
|
|
3b32210ef4 | ||
|
|
21b9f6d1af | ||
|
|
977a087bb3 | ||
|
|
e95299dac5 | ||
|
|
7ae3a85f21 | ||
|
|
c38b5aa2d4 |
6
.github/actions/build-deps/action.yml
vendored
6
.github/actions/build-deps/action.yml
vendored
@@ -21,6 +21,10 @@ inputs:
|
|||||||
description: "The logging verbosity."
|
description: "The logging verbosity."
|
||||||
required: false
|
required: false
|
||||||
default: "verbose"
|
default: "verbose"
|
||||||
|
sanitizers:
|
||||||
|
description: "The sanitizers to enable ('Address', 'Thread')."
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
@@ -33,11 +37,13 @@ runs:
|
|||||||
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
|
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
|
||||||
BUILD_TYPE: ${{ inputs.build_type }}
|
BUILD_TYPE: ${{ inputs.build_type }}
|
||||||
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
|
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
|
||||||
|
SANITIZERS: ${{ inputs.sanitizers }}
|
||||||
run: |
|
run: |
|
||||||
echo 'Installing dependencies.'
|
echo 'Installing dependencies.'
|
||||||
mkdir -p "${BUILD_DIR}"
|
mkdir -p "${BUILD_DIR}"
|
||||||
cd "${BUILD_DIR}"
|
cd "${BUILD_DIR}"
|
||||||
conan install \
|
conan install \
|
||||||
|
--profile ci \
|
||||||
--output-folder . \
|
--output-folder . \
|
||||||
--build="${BUILD_OPTION}" \
|
--build="${BUILD_OPTION}" \
|
||||||
--options:host='&:tests=True' \
|
--options:host='&:tests=True' \
|
||||||
|
|||||||
2
.github/actions/setup-conan/action.yml
vendored
2
.github/actions/setup-conan/action.yml
vendored
@@ -28,7 +28,7 @@ runs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo 'Installing profile.'
|
echo 'Installing profile.'
|
||||||
conan config install conan/profiles/default -tf $(conan config home)/profiles/
|
conan config install conan/profiles/ -tf $(conan config home)/profiles/
|
||||||
|
|
||||||
echo 'Conan profile:'
|
echo 'Conan profile:'
|
||||||
conan profile show
|
conan profile show
|
||||||
|
|||||||
156
.github/scripts/strategy-matrix/generate.py
vendored
156
.github/scripts/strategy-matrix/generate.py
vendored
@@ -209,15 +209,17 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
|||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Enable code coverage for Debian Bookworm using GCC 15 in Debug and no
|
cxx_flags = "-g"
|
||||||
|
# Enable code coverage for Debian Bookworm using GCC 14 in Debug and no
|
||||||
# Unity on linux/amd64
|
# Unity on linux/amd64
|
||||||
if (
|
if (
|
||||||
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
|
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"
|
||||||
and build_type == "Debug"
|
and build_type == "Debug"
|
||||||
and "-Dunity=OFF" in cmake_args
|
and "-Dunity=OFF" in cmake_args
|
||||||
and architecture["platform"] == "linux/amd64"
|
and architecture["platform"] == "linux/amd64"
|
||||||
):
|
):
|
||||||
cmake_args = f"-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}"
|
cmake_args = f"-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 {cmake_args}"
|
||||||
|
cxx_flags = f"-O0 {cxx_flags}"
|
||||||
|
|
||||||
# Generate a unique name for the configuration, e.g. macos-arm64-debug
|
# Generate a unique name for the configuration, e.g. macos-arm64-debug
|
||||||
# or debian-bookworm-gcc-12-amd64-release-unity.
|
# or debian-bookworm-gcc-12-amd64-release-unity.
|
||||||
@@ -229,7 +231,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
|||||||
if (n := os["compiler_version"]) != "":
|
if (n := os["compiler_version"]) != "":
|
||||||
config_name += f"-{n}"
|
config_name += f"-{n}"
|
||||||
config_name += (
|
config_name += (
|
||||||
f"-{architecture['platform'][architecture['platform'].find('/') + 1 :]}"
|
f"-{architecture['platform'][architecture['platform'].find('/')+1:]}"
|
||||||
)
|
)
|
||||||
config_name += f"-{build_type.lower()}"
|
config_name += f"-{build_type.lower()}"
|
||||||
if "-Dunity=ON" in cmake_args:
|
if "-Dunity=ON" in cmake_args:
|
||||||
@@ -238,21 +240,145 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
|||||||
# Add the configuration to the list, with the most unique fields first,
|
# Add the configuration to the list, with the most unique fields first,
|
||||||
# so that they are easier to identify in the GitHub Actions UI, as long
|
# so that they are easier to identify in the GitHub Actions UI, as long
|
||||||
# names get truncated.
|
# names get truncated.
|
||||||
configurations.append(
|
# Add Address and Thread (both coupled with UB) sanitizers when the distro is bookworm.
|
||||||
{
|
if os[
|
||||||
"config_name": config_name,
|
"distro_version"
|
||||||
"cmake_args": cmake_args,
|
] == "bookworm" and f"{os['compiler_name']}-{os['compiler_version']}" in {
|
||||||
"cmake_target": cmake_target,
|
"gcc-15",
|
||||||
"build_only": build_only,
|
"clang-20",
|
||||||
"build_type": build_type,
|
}:
|
||||||
"os": os,
|
configs = addSanitizerConfigs(architecture, os, cmake_args, cxx_flags)
|
||||||
"architecture": architecture,
|
if "asan_ubsan" in configs:
|
||||||
}
|
configurations.append(
|
||||||
)
|
{
|
||||||
|
"config_name": config_name + "-asan-ubsan",
|
||||||
|
"cmake_args": configs["asan_ubsan"],
|
||||||
|
"cmake_target": cmake_target,
|
||||||
|
"build_only": build_only,
|
||||||
|
"build_type": build_type,
|
||||||
|
"os": os,
|
||||||
|
"architecture": architecture,
|
||||||
|
"sanitizers": "Address,UndefinedBehavior",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if "tsan_ubsan" in configs:
|
||||||
|
configurations.append(
|
||||||
|
{
|
||||||
|
"config_name": config_name + "-tsan-ubsan",
|
||||||
|
"cmake_args": configs["tsan_ubsan"],
|
||||||
|
"cmake_target": cmake_target,
|
||||||
|
"build_only": build_only,
|
||||||
|
"build_type": build_type,
|
||||||
|
"os": os,
|
||||||
|
"architecture": architecture,
|
||||||
|
"sanitizers": "Thread,UndefinedBehavior",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
configurations.append(
|
||||||
|
{
|
||||||
|
"config_name": config_name,
|
||||||
|
"cmake_args": cmake_args,
|
||||||
|
"cmake_target": cmake_target,
|
||||||
|
"build_only": build_only,
|
||||||
|
"build_type": build_type,
|
||||||
|
"os": os,
|
||||||
|
"architecture": architecture,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return configurations
|
return configurations
|
||||||
|
|
||||||
|
|
||||||
|
def addSanitizerConfigs(
|
||||||
|
architecture: dict,
|
||||||
|
os: dict,
|
||||||
|
cmake_args: str,
|
||||||
|
cxx_flags: str,
|
||||||
|
) -> dict:
|
||||||
|
extra_warning_flags = ""
|
||||||
|
linker_relocation_flags = ""
|
||||||
|
linker_flags = ""
|
||||||
|
|
||||||
|
# Use large code model to avoid relocation errors with large binaries
|
||||||
|
# Only for x86-64 (amd64) - ARM64 doesn't support -mcmodel=large
|
||||||
|
if architecture["platform"] == "linux/amd64" and os["compiler_name"] == "gcc":
|
||||||
|
# Add -mcmodel=large to both compiler AND linker flags
|
||||||
|
# This is needed because sanitizers create very large binaries and
|
||||||
|
# large model removes the 2GB limitation that medium model has
|
||||||
|
cxx_flags += " -mcmodel=large -fno-PIC"
|
||||||
|
linker_relocation_flags += " -mcmodel=large -fno-PIC"
|
||||||
|
|
||||||
|
# Create default sanitizer flags
|
||||||
|
sanitizers_flags = "undefined,float-divide-by-zero"
|
||||||
|
|
||||||
|
if os["compiler_name"] == "gcc":
|
||||||
|
# Suppress false positive warnings in GCC with stringop-overflow
|
||||||
|
extra_warning_flags += " -Wno-stringop-overflow"
|
||||||
|
# Disable mold, gold and lld linkers.
|
||||||
|
# Use default linker (bfd/ld) which is more lenient with mixed code models
|
||||||
|
cmake_args += " -Duse_mold=OFF -Duse_gold=OFF -Duse_lld=OFF"
|
||||||
|
# Add linker flags for Sanitizers
|
||||||
|
linker_flags += f" -DCMAKE_EXE_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=address,{sanitizers_flags}'"
|
||||||
|
linker_flags += f" -DCMAKE_SHARED_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=address,{sanitizers_flags}'"
|
||||||
|
elif os["compiler_name"] == "clang":
|
||||||
|
# Note: We use $GITHUB_WORKSPACE environment variable which will be expanded by the shell
|
||||||
|
# before CMake processes it. This ensures the compiler receives an absolute path.
|
||||||
|
# CMAKE_SOURCE_DIR won't work here because it's inside CMAKE_CXX_FLAGS string.
|
||||||
|
# GCC doesn't support ignorelist.
|
||||||
|
cxx_flags += " -fsanitize-ignorelist=$GITHUB_WORKSPACE/sanitizers/suppressions/sanitizer-ignorelist.txt"
|
||||||
|
sanitizers_flags = f"{sanitizers_flags},unsigned-integer-overflow"
|
||||||
|
linker_flags += (
|
||||||
|
f" -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=address,{sanitizers_flags}'"
|
||||||
|
)
|
||||||
|
linker_flags += (
|
||||||
|
f" -DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=address,{sanitizers_flags}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Sanitizers recommend minimum of -O1 for reasonable performance
|
||||||
|
cxx_flags += " -O1"
|
||||||
|
|
||||||
|
# First create config for asan
|
||||||
|
cmake_args_flags = f'{cmake_args} -DCMAKE_CXX_FLAGS="-fsanitize=address,{sanitizers_flags} -fno-omit-frame-pointer {cxx_flags} {extra_warning_flags}" {linker_flags}'
|
||||||
|
|
||||||
|
# Add config with asan+ubsan
|
||||||
|
configs = {}
|
||||||
|
configs["asan_ubsan"] = cmake_args_flags
|
||||||
|
|
||||||
|
# Since TSAN runs are crashing with seg faults(could be compatibility issues with latest compilers)
|
||||||
|
# We deactivate it for now. But I would keep the code, since it took some effort to find the correct set of config needed to run this.
|
||||||
|
# This will be useful when we decide to activate it again in future.
|
||||||
|
activateTSAN = False
|
||||||
|
if activateTSAN:
|
||||||
|
linker_flags = ""
|
||||||
|
# Update configs for tsan
|
||||||
|
# gcc doesn't supports atomic_thread_fence with tsan. Suppress warnings.
|
||||||
|
# Also tsan doesn't work well with mcmode=large and bfd linker
|
||||||
|
if os["compiler_name"] == "gcc":
|
||||||
|
extra_warning_flags += " -Wno-tsan"
|
||||||
|
cxx_flags = cxx_flags.replace("-mcmodel=large", "-mcmodel=medium")
|
||||||
|
linker_relocation_flags = linker_relocation_flags.replace(
|
||||||
|
"-mcmodel=large", "-mcmodel=medium"
|
||||||
|
)
|
||||||
|
# Add linker flags for Sanitizers
|
||||||
|
linker_flags += f" -DCMAKE_EXE_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=thread,{sanitizers_flags}'"
|
||||||
|
linker_flags += f" -DCMAKE_SHARED_LINKER_FLAGS='{linker_relocation_flags} -fsanitize=thread,{sanitizers_flags}'"
|
||||||
|
elif os["compiler_name"] == "clang":
|
||||||
|
linker_flags += (
|
||||||
|
f" -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=thread,{sanitizers_flags}'"
|
||||||
|
)
|
||||||
|
linker_flags += (
|
||||||
|
f" -DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=thread,{sanitizers_flags}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
cmake_args_flags = f"{cmake_args} -DCMAKE_CXX_FLAGS='-fsanitize=thread,{sanitizers_flags} -fno-omit-frame-pointer {cxx_flags} {extra_warning_flags}' {linker_flags}"
|
||||||
|
|
||||||
|
# Add config with tsan+ubsan
|
||||||
|
configs["tsan_ubsan"] = cmake_args_flags
|
||||||
|
|
||||||
|
return configs
|
||||||
|
|
||||||
|
|
||||||
def read_config(file: Path) -> Config:
|
def read_config(file: Path) -> Config:
|
||||||
config = json.loads(file.read_text())
|
config = json.loads(file.read_text())
|
||||||
if (
|
if (
|
||||||
|
|||||||
24
.github/workflows/reusable-build-test-config.yml
vendored
24
.github/workflows/reusable-build-test-config.yml
vendored
@@ -50,6 +50,12 @@ on:
|
|||||||
type: number
|
type: number
|
||||||
default: 2
|
default: 2
|
||||||
|
|
||||||
|
sanitizers:
|
||||||
|
description: "The sanitizers to enable ('Address+UndefinedBehavior' or 'Thread+UndefinedBehavior')."
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
CODECOV_TOKEN:
|
CODECOV_TOKEN:
|
||||||
description: "The Codecov token to use for uploading coverage reports."
|
description: "The Codecov token to use for uploading coverage reports."
|
||||||
@@ -68,6 +74,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
ENABLED_VOIDSTAR: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
ENABLED_VOIDSTAR: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
||||||
ENABLED_COVERAGE: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
|
ENABLED_COVERAGE: ${{ contains(inputs.cmake_args, '-Dcoverage=ON') }}
|
||||||
|
ENABLED_SANITIZERS: ${{ contains(inputs.cmake_args, '-fsanitize') }}
|
||||||
steps:
|
steps:
|
||||||
- name: Cleanup workspace (macOS and Windows)
|
- name: Cleanup workspace (macOS and Windows)
|
||||||
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }}
|
||||||
@@ -102,19 +109,18 @@ jobs:
|
|||||||
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
||||||
# amount of logs. For other OSes, the "verbose" logs are more useful.
|
# amount of logs. For other OSes, the "verbose" logs are more useful.
|
||||||
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||||
|
sanitizers: ${{ inputs.sanitizers }}
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
working-directory: ${{ inputs.build_dir }}
|
working-directory: ${{ inputs.build_dir }}
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: ${{ inputs.build_type }}
|
BUILD_TYPE: ${{ inputs.build_type }}
|
||||||
CMAKE_ARGS: ${{ inputs.cmake_args }}
|
|
||||||
run: |
|
run: |
|
||||||
cmake \
|
cmake .. \
|
||||||
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
|
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
|
||||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||||
${CMAKE_ARGS} \
|
${{ inputs.cmake_args }}
|
||||||
..
|
|
||||||
|
|
||||||
- name: Build the binary
|
- name: Build the binary
|
||||||
working-directory: ${{ inputs.build_dir }}
|
working-directory: ${{ inputs.build_dir }}
|
||||||
@@ -141,7 +147,7 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Check linking (Linux)
|
- name: Check linking (Linux)
|
||||||
if: ${{ runner.os == 'Linux' }}
|
if: ${{ runner.os == 'Linux' && env.ENABLED_SANITIZERS == 'false' }}
|
||||||
working-directory: ${{ inputs.build_dir }}
|
working-directory: ${{ inputs.build_dir }}
|
||||||
run: |
|
run: |
|
||||||
ldd ./rippled
|
ldd ./rippled
|
||||||
@@ -166,6 +172,10 @@ jobs:
|
|||||||
BUILD_TYPE: ${{ inputs.build_type }}
|
BUILD_TYPE: ${{ inputs.build_type }}
|
||||||
PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }}
|
PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }}
|
||||||
run: |
|
run: |
|
||||||
|
export ASAN_OPTIONS="detect_container_overflow=0 suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/asan.supp"
|
||||||
|
export TSAN_OPTIONS="second_deadlock_stack=1 halt_on_error=0 suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/tsan.supp"
|
||||||
|
export UBSAN_OPTIONS="suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/ubsan.supp"
|
||||||
|
export LSAN_OPTIONS="suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/lsan.supp"
|
||||||
ctest \
|
ctest \
|
||||||
--output-on-failure \
|
--output-on-failure \
|
||||||
-C "${BUILD_TYPE}" \
|
-C "${BUILD_TYPE}" \
|
||||||
@@ -177,6 +187,10 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||||
run: |
|
run: |
|
||||||
|
export ASAN_OPTIONS="detect_container_overflow=0 suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/asan.supp"
|
||||||
|
export TSAN_OPTIONS="second_deadlock_stack=1 halt_on_error=0 suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/tsan.supp"
|
||||||
|
export UBSAN_OPTIONS="suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/ubsan.supp"
|
||||||
|
export LSAN_OPTIONS="suppressions=$GITHUB_WORKSPACE/sanitizers/suppressions/lsan.supp"
|
||||||
./rippled --unittest --unittest-jobs "${BUILD_NPROC}"
|
./rippled --unittest --unittest-jobs "${BUILD_NPROC}"
|
||||||
|
|
||||||
- name: Debug failure (Linux)
|
- name: Debug failure (Linux)
|
||||||
|
|||||||
1
.github/workflows/reusable-build-test.yml
vendored
1
.github/workflows/reusable-build-test.yml
vendored
@@ -54,5 +54,6 @@ jobs:
|
|||||||
runs_on: ${{ toJSON(matrix.architecture.runner) }}
|
runs_on: ${{ toJSON(matrix.architecture.runner) }}
|
||||||
image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }}
|
image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }}
|
||||||
config_name: ${{ matrix.config_name }}
|
config_name: ${{ matrix.config_name }}
|
||||||
|
sanitizers: ${{ matrix.sanitizers }}
|
||||||
secrets:
|
secrets:
|
||||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|||||||
14
BUILD.md
14
BUILD.md
@@ -370,6 +370,20 @@ tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
|
|||||||
conan install .. --output-folder . --build missing --settings build_type=Debug
|
conan install .. --output-folder . --build missing --settings build_type=Debug
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you would like to activate `asan`(`Address`) or `tsan`(`Thread`) or `ubsan`(`UndefinedBehavior`) for the build,
|
||||||
|
declare an environment variable as follows(with values: `Address`, `Thread`, `UndefinedBehavior`) and use the `sanitizers`
|
||||||
|
profile in the `conan install` command.
|
||||||
|
|
||||||
|
```
|
||||||
|
SANITIZERS=Address conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
|
||||||
|
# or if you want asan+ubsan
|
||||||
|
SANITIZERS=Address,UndefinedBehavior conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Do not mix Address and Thread, that's incompatible.
|
||||||
|
|
||||||
|
More details here: [sanitizers](./docs/build/sanitizers.md)
|
||||||
|
|
||||||
To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug`
|
To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug`
|
||||||
|
|
||||||
For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`,
|
For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`,
|
||||||
|
|||||||
1
conan/profiles/ci
Normal file
1
conan/profiles/ci
Normal file
@@ -0,0 +1 @@
|
|||||||
|
include(sanitizers)
|
||||||
59
conan/profiles/sanitizers
Normal file
59
conan/profiles/sanitizers
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
include(default)
|
||||||
|
{% set compiler, version, compiler_exe = detect_api.detect_default_compiler() %}
|
||||||
|
{% 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 model_code = "" %}
|
||||||
|
{% set extra_cxxflags = "-fno-omit-frame-pointer -fno-PIC -O1 -Wno-stringop-overflow" %}
|
||||||
|
|
||||||
|
{% if "Address" in sanitizers %}
|
||||||
|
{% set _ = sanitizer_list.append("address") %}
|
||||||
|
{% set model_code = "-mcmodel=large" %}
|
||||||
|
{% elif "Thread" in sanitizers %}
|
||||||
|
{% set _ = sanitizer_list.append("thread") %}
|
||||||
|
{% set model_code = "-mcmodel=medium" %}
|
||||||
|
{% set extra_cxxflags = extra_cxxflags ~ " -Wno-tsan" %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if "UndefinedBehavior" in sanitizers or "UndefinedBehavior" in sanitizers %}
|
||||||
|
{% set _ = sanitizer_list.append("undefined") %}
|
||||||
|
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) ~ " " ~ model_code %}
|
||||||
|
|
||||||
|
tools.build:cxxflags+=['{{sanitizer_flags}} {{extra_cxxflags}}']
|
||||||
|
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||||
|
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||||
|
{% endif %}
|
||||||
|
{% elif compiler == "apple-clang" or compiler == "clang" %}
|
||||||
|
{% if "Address" in sanitizers or "Thread" in sanitizers or "UndefinedBehavior" in sanitizers %}
|
||||||
|
{% set sanitizer_list = [] %}
|
||||||
|
{% set extra_cxxflags = "-fno-omit-frame-pointer -fno-PIC -O1" %}
|
||||||
|
|
||||||
|
{% if "Address" in sanitizers %}
|
||||||
|
{% set _ = sanitizer_list.append("address") %}
|
||||||
|
{% elif "Thread" in sanitizers %}
|
||||||
|
{% set _ = sanitizer_list.append("thread") %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% 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 %}
|
||||||
|
|
||||||
|
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) %}
|
||||||
|
|
||||||
|
tools.build:cxxflags+=['{{sanitizer_flags}} {{extra_cxxflags}}']
|
||||||
|
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||||
|
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags"]
|
||||||
183
docs/build/sanitizers.md
vendored
Normal file
183
docs/build/sanitizers.md
vendored
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Sanitizer Configuration for Rippled
|
||||||
|
|
||||||
|
This document explains how to properly configure and run sanitizers (AddressSanitizer, UndefinedBehaviorSanitizer, ThreadSanitizer) with the rippled project.
|
||||||
|
Corresponding suppression files are located in the `sanitizers/suppressions` directory.
|
||||||
|
|
||||||
|
- [Sanitizer Configuration for Rippled](#sanitizer-configuration-for-rippled)
|
||||||
|
- [Building with Sanitizers](#building-with-sanitizers)
|
||||||
|
- [AddressSanitizer (ASan) + UndefinedBehaviorSanitizer (UBSan)](#addresssanitizer-asan--undefinedbehaviorsanitizer-ubsan)
|
||||||
|
- [ThreadSanitizer (TSan) + UndefinedBehaviorSanitizer (UBSan)](#threadsanitizer-tsan--undefinedbehaviorsanitizer-ubsan)
|
||||||
|
- [Just UndefinedBehaviorSanitizer (UBSan)](#just-undefinedbehaviorsanitizer-ubsan)
|
||||||
|
- [Running Tests with Sanitizers](#running-tests-with-sanitizers)
|
||||||
|
- [AddressSanitizer (ASan)](#addresssanitizer-asan)
|
||||||
|
- [ThreadSanitizer (TSan)](#threadsanitizer-tsan)
|
||||||
|
- [LeakSanitizer (LSan)](#leaksanitizer-lsan)
|
||||||
|
- [Suppression Files](#suppression-files)
|
||||||
|
- [asan.supp](#asansupp)
|
||||||
|
- [lsan.supp](#lsansupp)
|
||||||
|
- [ubsan.supp](#ubsansupp)
|
||||||
|
- [tsan.supp](#tsansupp)
|
||||||
|
- [Ignorelist](#sanitizer-ignorelisttxt)
|
||||||
|
- [Known False Positives](#known-false-positives)
|
||||||
|
- [References](#references)
|
||||||
|
|
||||||
|
## Building with Sanitizers
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Follow the same instructions as mentioned in [BUILD.md](../../BUILD.md) but with following changes:
|
||||||
|
|
||||||
|
1. Make sure you have clean build directory.
|
||||||
|
2. Use `--profile sanitizers` to configure build options to include sanitizer flags. [sanitizes](../../conan/profiles/sanitizers) profile contains settings for all sanitizers.
|
||||||
|
3. Set `ASAN_OPTIONS`, `LSAN_OPTIONS` ,`UBSAN_OPTIONS` and `TSAN_OPTIONS` environment variables to configure sanitizer behavior when running executables.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Build steps:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/rippled
|
||||||
|
rm -rf .build
|
||||||
|
mkdir .build
|
||||||
|
cd .build
|
||||||
|
```
|
||||||
|
|
||||||
|
#### AddressSanitizer (ASan) + UndefinedBehaviorSanitizer (UBSan)
|
||||||
|
|
||||||
|
Build with AddressSanitizer+UndefinedBehavior sanitizers (or you can choose just one of them).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SANITIZERS=Address,UndefinedBehavior conan install .. --output-folder . --profile sanitizers --build missing --settings build_type=Release
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ThreadSanitizer (TSan) + UndefinedBehaviorSanitizer (UBSan)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build dependencies with Thread sanitizer
|
||||||
|
SANITIZERS=Thread,UndefinedBehavior conan install .. --output-folder . --profile sanitizers --build missing --settings build_type=Release
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Just UndefinedBehaviorSanitizer (UBSan)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build dependencies with Thread sanitizer
|
||||||
|
SANITIZERS=UndefinedBehavior conan install .. --output-folder . --profile sanitizers --build missing --settings build_type=Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `--profile:all sanitizers` if you would like to build all dependencies and libraries (boost etc.) with sanitizers. This might take long time but you won't see some false-positives on sanitizer reports since whole binary will be instrumented.
|
||||||
|
|
||||||
|
To build with Thread+UndefinedBehavior Sanitizer, replace `SANITIZERS=Address` with `SANITIZERS=Thread`.
|
||||||
|
|
||||||
|
# Configure CMake
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dunity=ON -Dtests=ON -Dxrpld=ON
|
||||||
|
|
||||||
|
# Build
|
||||||
|
cmake --build . --parallel 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running Tests with Sanitizers
|
||||||
|
|
||||||
|
### AddressSanitizer (ASan)
|
||||||
|
|
||||||
|
**IMPORTANT**: ASan with Boost produces many false positives. Use these options:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ASAN_OPTIONS="detect_container_overflow=0 suppressions=path/to/asan.supp halt_on_error=0 log_path=asan.log"
|
||||||
|
export UBSAN_OPTIONS="suppressions=path/to/ubsan.supp print_stacktrace=1 halt_on_error=0 log_path=ubsan.log"
|
||||||
|
export LSAN_OPTIONS="suppressions=path/to/lsan.supp halt_on_error=0 log_path=lsan.log"
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
./rippled --unittest --unittest-jobs=5
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why `detect_container_overflow=0`?**
|
||||||
|
|
||||||
|
- Boost intrusive containers (used in `aged_unordered_container`) trigger false positives
|
||||||
|
- Boost context switching (used in `Workers.cpp`) confuses ASan's stack tracking
|
||||||
|
- Since we usually don't build boost(because we don't want to instrument boost and detect issues in boost code) with asan but use boost containers in ASAN instrumented rippled code, it generates false positives.
|
||||||
|
- See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow
|
||||||
|
|
||||||
|
### ThreadSanitizer (TSan) + UndefinedBehaviorSanitizer (UBSan)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export TSAN_OPTIONS="suppressions=path/to/tsan.supp halt_on_error=0 log_path=tsan.log"
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
./rippled --unittest --unittest-jobs=5
|
||||||
|
```
|
||||||
|
|
||||||
|
### LeakSanitizer (LSan)
|
||||||
|
|
||||||
|
LSan is automatically enabled with ASan. To disable it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export ASAN_OPTIONS="detect_leaks=0"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Suppression Files
|
||||||
|
|
||||||
|
### `asan.supp`
|
||||||
|
|
||||||
|
- **Purpose**: Suppress AddressSanitizer (ASan) errors only
|
||||||
|
- **Format**: `interceptor_name:<pattern>` where pattern matches file names. Supported suppression types are:
|
||||||
|
- interceptor_name
|
||||||
|
- interceptor_via_fun
|
||||||
|
- interceptor_via_lib
|
||||||
|
- odr_violation
|
||||||
|
- **More info**: [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer)
|
||||||
|
- **Note**: Cannot suppress stack-buffer-overflow, container-overflow, etc.
|
||||||
|
|
||||||
|
### `lsan.supp`
|
||||||
|
|
||||||
|
- **Purpose**: Suppress LeakSanitizer (LSan) errors only
|
||||||
|
- **Format**: `leak:<pattern>` where pattern matches function/file names
|
||||||
|
- **More info**: [LeakSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer)
|
||||||
|
|
||||||
|
### `ubsan.supp`
|
||||||
|
|
||||||
|
- **Purpose**: Suppress UndefinedBehaviorSanitizer errors
|
||||||
|
- **Format**: `<error_type>:<pattern>` (e.g., `unsigned-integer-overflow:protobuf`)
|
||||||
|
- **Covers**: Intentional overflows in sanitizers/suppressions libraries (protobuf, gRPC, stdlib)
|
||||||
|
|
||||||
|
### `tsan.supp`
|
||||||
|
|
||||||
|
- **Purpose**: Suppress ThreadSanitizer data race warnings
|
||||||
|
- **Format**: `race:<pattern>` where pattern matches function/file names
|
||||||
|
- **More info**: [ThreadSanitizerSuppressions](https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions)
|
||||||
|
|
||||||
|
### `sanitizer-ignorelist.txt`
|
||||||
|
|
||||||
|
- **Purpose**: Compile-time ignorelist for all sanitizers
|
||||||
|
- **Usage**: Passed via `-fsanitize-ignorelist=absolute/path/to/sanitizer-ignorelist.txt`
|
||||||
|
- **Format**: `<level>:<pattern>` (e.g., `src:Workers.cpp`)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "ASan is ignoring requested \_\_asan_handle_no_return" warnings
|
||||||
|
|
||||||
|
These warnings appear when using Boost context switching and are harmless. They indicate potential false positives.
|
||||||
|
|
||||||
|
### Sanitizer Mismatch Errors
|
||||||
|
|
||||||
|
If you see undefined symbols like `___tsan_atomic_load` when building with ASan:
|
||||||
|
|
||||||
|
**Problem**: Dependencies were built with a different sanitizer than the main project.
|
||||||
|
|
||||||
|
**Solution**: Rebuild everything with the same sanitizer:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf .build
|
||||||
|
# Then follow the build instructions above
|
||||||
|
```
|
||||||
|
|
||||||
|
Then review the log files: `asan.log.*`, `ubsan.log.*`, `tsan.log.*`
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [AddressSanitizer Wiki](https://github.com/google/sanitizers/wiki/AddressSanitizer)
|
||||||
|
- [AddressSanitizer Flags](https://github.com/google/sanitizers/wiki/AddressSanitizerFlags)
|
||||||
|
- [Container Overflow Detection](https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow)
|
||||||
|
- [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html)
|
||||||
|
- [ThreadSanitizer](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual)
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#ifndef XRPL_BASICS_MALLOCTRIM_H_INCLUDED
|
|
||||||
#define XRPL_BASICS_MALLOCTRIM_H_INCLUDED
|
|
||||||
|
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Allocator interaction note:
|
|
||||||
// - This facility invokes glibc's malloc_trim(0) on Linux/glibc to request that
|
|
||||||
// ptmalloc return free heap pages to the OS.
|
|
||||||
// - If an alternative allocator (e.g. jemalloc or tcmalloc) is linked or
|
|
||||||
// preloaded (LD_PRELOAD), calling glibc's malloc_trim typically has no effect
|
|
||||||
// on the *active* heap. The call is harmless but may not reclaim memory
|
|
||||||
// because those allocators manage their own arenas.
|
|
||||||
// - Only glibc sbrk/arena space is eligible for trimming; large mmap-backed
|
|
||||||
// allocations are usually returned to the OS on free regardless of trimming.
|
|
||||||
// - Call at known reclamation points (e.g., after cache sweeps / online delete)
|
|
||||||
// and consider rate limiting to avoid churn.
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
struct MallocTrimReport
|
|
||||||
{
|
|
||||||
bool supported{false};
|
|
||||||
int trimResult{-1};
|
|
||||||
long rssBeforeKB{-1};
|
|
||||||
long rssAfterKB{-1};
|
|
||||||
|
|
||||||
[[nodiscard]] long
|
|
||||||
deltaKB() const noexcept
|
|
||||||
{
|
|
||||||
if (rssBeforeKB < 0 || rssAfterKB < 0)
|
|
||||||
return 0;
|
|
||||||
return rssAfterKB - rssBeforeKB;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Attempt to return freed memory to the operating system.
|
|
||||||
*
|
|
||||||
* On Linux with glibc malloc, this issues ::malloc_trim(0), which may release
|
|
||||||
* free space from ptmalloc arenas back to the kernel. On other platforms, or if
|
|
||||||
* a different allocator is in use, this function is a no-op and the report will
|
|
||||||
* indicate that trimming is unsupported or had no effect.
|
|
||||||
*
|
|
||||||
* @param tag Optional identifier for logging/debugging purposes.
|
|
||||||
* @param journal Journal for diagnostic logging.
|
|
||||||
* @return Report containing before/after metrics and the trim result.
|
|
||||||
*
|
|
||||||
* @note If an alternative allocator (jemalloc/tcmalloc) is linked or preloaded,
|
|
||||||
* calling glibc's malloc_trim may have no effect on the active heap. The
|
|
||||||
* call is harmless but typically does not reclaim memory under those
|
|
||||||
* allocators.
|
|
||||||
*
|
|
||||||
* @note Only memory served from glibc's sbrk/arena heaps is eligible for trim.
|
|
||||||
* Large allocations satisfied via mmap are usually returned on free
|
|
||||||
* independently of trimming.
|
|
||||||
*
|
|
||||||
* @note Intended for use after operations that free significant memory (e.g.,
|
|
||||||
* cache sweeps, ledger cleanup, online delete). Consider rate limiting.
|
|
||||||
*/
|
|
||||||
MallocTrimReport
|
|
||||||
mallocTrim(std::optional<std::string> const& tag, beast::Journal journal);
|
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
|
|
||||||
#endif
|
|
||||||
32
sanitizers/suppressions/asan.supp
Normal file
32
sanitizers/suppressions/asan.supp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions.
|
||||||
|
#
|
||||||
|
# ASAN_OPTIONS="detect_container_overflow=0 suppressions=sanitizers/suppressions/asan.supp halt_on_error=0"
|
||||||
|
#
|
||||||
|
# The detect_container_overflow=0 option disables false positives from:
|
||||||
|
# - Boost intrusive containers (slist_iterator.hpp, hashtable.hpp, aged_unordered_container.h)
|
||||||
|
# - Boost context/coroutine stack switching (Workers.cpp, thread.h)
|
||||||
|
#
|
||||||
|
# See: https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow
|
||||||
|
|
||||||
|
# Suprpress voilations in sanitizers/suppressions code
|
||||||
|
interceptor_name:^sanitizers/suppressions
|
||||||
|
|
||||||
|
# Boost
|
||||||
|
interceptor_name:boost/asio
|
||||||
|
|
||||||
|
# Leaks in Doctest tests: xrpl.test.*
|
||||||
|
interceptor_name:src/libxrpl/net/HTTPClient.cpp
|
||||||
|
interceptor_name:src/libxrpl/net/RegisterSSLCerts.cpp
|
||||||
|
interceptor_name:src/tests/libxrpl/net/HTTPClient.cpp
|
||||||
|
interceptor_name:xrpl/net/AutoSocket.h
|
||||||
|
interceptor_name:xrpl/net/HTTPClient.h
|
||||||
|
interceptor_name:xrpl/net/HTTPClientSSLContext.h
|
||||||
|
interceptor_name:xrpl/net/RegisterSSLCerts.h
|
||||||
|
|
||||||
|
# Suppress false positive stack-buffer errors in thread stack allocation
|
||||||
|
# Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189)
|
||||||
|
# These occur during multi-threaded test initialization on macOS
|
||||||
|
interceptor_name:memcpy
|
||||||
|
interceptor_name:__bzero
|
||||||
|
interceptor_name:__asan_memset
|
||||||
|
interceptor_name:__asan_memcpy
|
||||||
16
sanitizers/suppressions/lsan.supp
Normal file
16
sanitizers/suppressions/lsan.supp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions.
|
||||||
|
|
||||||
|
# Suppress leaks detected by asan in rippled code.
|
||||||
|
leak:src/libxrpl/net/HTTPClient.cpp
|
||||||
|
leak:src/libxrpl/net/RegisterSSLCerts.cpp
|
||||||
|
leak:src/tests/libxrpl/net/HTTPClient.cpp
|
||||||
|
leak:xrpl/net/AutoSocket.h
|
||||||
|
leak:xrpl/net/HTTPClient.h
|
||||||
|
leak:xrpl/net/HTTPClientSSLContext.h
|
||||||
|
leak:xrpl/net/RegisterSSLCerts.h
|
||||||
|
leak:ripple::HTTPClient
|
||||||
|
leak:ripple::HTTPClientImp
|
||||||
|
|
||||||
|
# Suppress leaks detected by asan in boost code.
|
||||||
|
leak:boost::asio
|
||||||
|
leak:boost/asio
|
||||||
27
sanitizers/suppressions/sanitizer-ignorelist.txt
Normal file
27
sanitizers/suppressions/sanitizer-ignorelist.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
deadlock:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
deadlock:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
deadlock:libxrpl/beast/utility/beast_PropertyStream.cpp
|
||||||
|
deadlock:test/beast/beast_PropertyStream_test.cpp
|
||||||
|
deadlock:xrpld/core/detail/Workers.cpp
|
||||||
|
deadlock:xrpld/core/JobQueue.cpp
|
||||||
|
|
||||||
|
race:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
race:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
race:libxrpl/beast/utility/beast_PropertyStream.cpp
|
||||||
|
race:test/beast/beast_PropertyStream_test.cpp
|
||||||
|
race:xrpld/core/detail/Workers.cpp
|
||||||
|
race:xrpld/core/JobQueue.cpp
|
||||||
|
|
||||||
|
signal:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
signal:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
signal:libxrpl/beast/utility/beast_PropertyStream.cpp
|
||||||
|
signal:test/beast/beast_PropertyStream_test.cpp
|
||||||
|
signal:xrpld/core/detail/Workers.cpp
|
||||||
|
signal:xrpld/core/JobQueue.cpp
|
||||||
|
|
||||||
|
src:beast/utility/beast_Journal.cpp
|
||||||
|
src:beast/utility/beast_PropertyStream.cpp
|
||||||
|
src:core/detail/Workers.cpp
|
||||||
|
src:core/JobQueue.cpp
|
||||||
|
src:libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
src:test/beast/beast_PropertyStream_test.cpp
|
||||||
102
sanitizers/suppressions/tsan.supp
Normal file
102
sanitizers/suppressions/tsan.supp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions.
|
||||||
|
|
||||||
|
# Suppress race in Boost ASIO scheduler detected by GCC-15
|
||||||
|
# This is a false positive in Boost's internal pipe() synchronization
|
||||||
|
race:boost/asio/
|
||||||
|
race:boost/context/
|
||||||
|
race:boost/asio/executor.hpp
|
||||||
|
race:boost::asio
|
||||||
|
|
||||||
|
# Suppress tsan related issues in rippled code.
|
||||||
|
race:src/libxrpl/basics/make_SSLContext.cpp
|
||||||
|
race:src/libxrpl/basics/Number.cpp
|
||||||
|
race:src/libxrpl/json/json_value.cpp
|
||||||
|
race:src/libxrpl/json/to_string.cpp
|
||||||
|
race:src/libxrpl/ledger/OpenView.cpp
|
||||||
|
race:src/libxrpl/net/HTTPClient.cpp
|
||||||
|
race:src/libxrpl/nodestore/backend/NuDBFactory.cpp
|
||||||
|
race:src/libxrpl/protocol/InnerObjectFormats.cpp
|
||||||
|
race:src/libxrpl/protocol/STParsedJSON.cpp
|
||||||
|
race:src/libxrpl/resource/ResourceManager.cpp
|
||||||
|
race:src/test/app/Flow_test.cpp
|
||||||
|
race:src/test/app/LedgerReplay_test.cpp
|
||||||
|
race:src/test/app/NFToken_test.cpp
|
||||||
|
race:src/test/app/Offer_test.cpp
|
||||||
|
race:src/test/app/ValidatorSite_test.cpp
|
||||||
|
race:src/test/consensus/NegativeUNL_test.cpp
|
||||||
|
race:src/test/jtx/impl/Env.cpp
|
||||||
|
race:src/test/jtx/impl/JSONRPCClient.cpp
|
||||||
|
race:src/test/jtx/impl/pay.cpp
|
||||||
|
race:src/test/jtx/impl/token.cpp
|
||||||
|
race:src/test/rpc/Book_test.cpp
|
||||||
|
race:src/xrpld/app/ledger/detail/InboundTransactions.cpp
|
||||||
|
race:src/xrpld/app/main/Application.cpp
|
||||||
|
race:src/xrpld/app/main/BasicApp.cpp
|
||||||
|
race:src/xrpld/app/main/GRPCServer.cpp
|
||||||
|
race:src/xrpld/app/misc/detail/AmendmentTable.cpp
|
||||||
|
race:src/xrpld/app/misc/FeeVoteImpl.cpp
|
||||||
|
race:src/xrpld/app/rdb/detail/Wallet.cpp
|
||||||
|
race:src/xrpld/overlay/detail/OverlayImpl.cpp
|
||||||
|
race:src/xrpld/peerfinder/detail/PeerfinderManager.cpp
|
||||||
|
race:src/xrpld/peerfinder/detail/SourceStrings.cpp
|
||||||
|
race:src/xrpld/rpc/detail/ServerHandler.cpp
|
||||||
|
race:xrpl/server/detail/Door.h
|
||||||
|
race:xrpl/server/detail/Spawn.h
|
||||||
|
race:xrpl/server/detail/ServerImpl.h
|
||||||
|
race:xrpl/nodestore/detail/DatabaseNodeImp.h
|
||||||
|
race:src/libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
race:src/test/beast/LexicalCast_test.cpp
|
||||||
|
race:ripple::ServerHandler
|
||||||
|
|
||||||
|
# More suppressions in external library code.
|
||||||
|
race:crtstuff.c
|
||||||
|
race:pipe
|
||||||
|
|
||||||
|
# Deadlock / lock-order-inversion suppressions
|
||||||
|
# Note: GCC's TSAN may not fully support all deadlock suppression patterns
|
||||||
|
deadlock:src/libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
deadlock:src/libxrpl/beast/utility/beast_PropertyStream.cpp
|
||||||
|
deadlock:src/test/beast/beast_PropertyStream_test.cpp
|
||||||
|
deadlock:src/xrpld/core/detail/Workers.cpp
|
||||||
|
deadlock:src/xrpld/app/misc/detail/Manifest.cpp
|
||||||
|
deadlock:src/xrpld/app/misc/detail/ValidatorList.cpp
|
||||||
|
deadlock:src/xrpld/app/misc/detail/ValidatorSite.cpp
|
||||||
|
|
||||||
|
signal:src/libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
signal:src/xrpld/core/detail/Workers.cpp
|
||||||
|
signal:src/xrpld/core/JobQueue.cpp
|
||||||
|
signal:ripple::Workers::Worker
|
||||||
|
|
||||||
|
# Aggressive suppressing of deadlock tsan errors
|
||||||
|
deadlock:pthread_create
|
||||||
|
deadlock:pthread_rwlock_rdlock
|
||||||
|
deadlock:boost::asio
|
||||||
|
|
||||||
|
# Suppress SEGV crashes in TSAN itself during stringbuf operations
|
||||||
|
# This appears to be a GCC-15 TSAN instrumentation issue with basic_stringbuf::str()
|
||||||
|
# Commonly triggered in beast::Journal::ScopedStream destructor
|
||||||
|
signal:std::__cxx11::basic_stringbuf
|
||||||
|
signal:basic_stringbuf
|
||||||
|
signal:basic_ostringstream
|
||||||
|
|
||||||
|
called_from_lib:libclang_rt
|
||||||
|
race:ostreambuf_iterator
|
||||||
|
race:basic_ostream
|
||||||
|
|
||||||
|
# Suppress SEGV in Boost ASIO memory allocation with GCC-15 TSAN
|
||||||
|
signal:boost::asio::aligned_new
|
||||||
|
signal:boost::asio::detail::memory
|
||||||
|
|
||||||
|
# Suppress SEGV in execute_native_thread_routine
|
||||||
|
signal:execute_native_thread_routine
|
||||||
|
|
||||||
|
# Suppress data race in Boost Context fiber management
|
||||||
|
# This is a false positive in Boost's exception state management during fiber context switching
|
||||||
|
race:__cxxabiv1::manage_exception_state
|
||||||
|
race:boost::context::fiber::resume
|
||||||
|
race:boost::asio::detail::spawned_fiber_thread
|
||||||
|
race:boost::asio::detail::spawned_fiber_thread::suspend_with
|
||||||
|
race:boost::asio::detail::spawned_fiber_thread::destroy
|
||||||
|
|
||||||
|
# Suppress data race in __tsan_memcpy called from Boost fiber operations
|
||||||
|
race:__tsan_memcpy
|
||||||
234
sanitizers/suppressions/ubsan.supp
Normal file
234
sanitizers/suppressions/ubsan.supp
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
# The idea is to empty this file gradually by fixing the underlying issues and removing suppresions.
|
||||||
|
|
||||||
|
# Suppress UBSan errors in external code by source file path
|
||||||
|
# This matches any source file under the external/ directory
|
||||||
|
alignment:external
|
||||||
|
bool:external
|
||||||
|
bounds:external
|
||||||
|
cfi:external
|
||||||
|
enum:external
|
||||||
|
float-cast-overflow:external
|
||||||
|
float-divide-by-zero:external
|
||||||
|
function:external
|
||||||
|
implicit-integer-sign-change:external
|
||||||
|
implicit-signed-integer-truncation::external
|
||||||
|
implicit-signed-integer-truncation:external
|
||||||
|
implicit-unsigned-integer-truncation:external
|
||||||
|
integer-divide-by-zero:external
|
||||||
|
invalid-builtin-use:external
|
||||||
|
invalid-objc-cast:external
|
||||||
|
nonnull-attribute:external
|
||||||
|
null:external
|
||||||
|
nullability-arg:external
|
||||||
|
nullability-assign:external
|
||||||
|
nullability-return:external
|
||||||
|
object-size:external
|
||||||
|
pointer-overflow:external
|
||||||
|
return:external
|
||||||
|
returns-nonnull-attribute:external
|
||||||
|
shift-base:external
|
||||||
|
shift-exponent:external
|
||||||
|
signed-integer-overflow:external
|
||||||
|
undefined:external
|
||||||
|
unreachable:external
|
||||||
|
unsigned-integer-overflow:external
|
||||||
|
vla-bound:external
|
||||||
|
vptr_check:external
|
||||||
|
vptr:external
|
||||||
|
|
||||||
|
# Suppress all UBSan errors in Boost libraries
|
||||||
|
# This matches any files containing "boost" in its path or name
|
||||||
|
alignment:boost
|
||||||
|
bool:boost
|
||||||
|
bounds:boost
|
||||||
|
cfi:boost
|
||||||
|
enum:boost
|
||||||
|
float-cast-overflow:boost
|
||||||
|
float-divide-by-zero:boost
|
||||||
|
function:boost
|
||||||
|
implicit-integer-sign-change:boost
|
||||||
|
implicit-signed-integer-truncation:boost
|
||||||
|
implicit-unsigned-integer-truncation:boost
|
||||||
|
integer-divide-by-zero:boost
|
||||||
|
invalid-builtin-use:boost
|
||||||
|
invalid-objc-cast:boost
|
||||||
|
nonnull-attribute:boost
|
||||||
|
null:boost
|
||||||
|
nullability-arg:boost
|
||||||
|
nullability-assign:boost
|
||||||
|
nullability-return:boost
|
||||||
|
object-size:boost
|
||||||
|
pointer-overflow:boost
|
||||||
|
return:boost
|
||||||
|
returns-nonnull-attribute:boost
|
||||||
|
shift-base:boost
|
||||||
|
shift-exponent:boost
|
||||||
|
signed-integer-overflow:boost
|
||||||
|
undefined:boost
|
||||||
|
unreachable:boost
|
||||||
|
unsigned-integer-overflow:boost
|
||||||
|
vla-bound:boost
|
||||||
|
vptr_check:boost
|
||||||
|
vptr:boost
|
||||||
|
|
||||||
|
# Google protobuf
|
||||||
|
undefined:protobuf
|
||||||
|
|
||||||
|
# Suppress UBSan errors in rippled code by source file path
|
||||||
|
undefined:src/libxrpl/basics/base64.cpp
|
||||||
|
undefined:src/libxrpl/basics/Number.cpp
|
||||||
|
undefined:src/libxrpl/beast/utility/beast_Journal.cpp
|
||||||
|
undefined:src/libxrpl/crypto/RFC1751.cpp
|
||||||
|
undefined:src/libxrpl/ledger/ApplyView.cpp
|
||||||
|
undefined:src/libxrpl/ledger/View.cpp
|
||||||
|
undefined:src/libxrpl/protocol/Permissions.cpp
|
||||||
|
undefined:src/libxrpl/protocol/STAmount.cpp
|
||||||
|
undefined:src/libxrpl/protocol/STPathSet.cpp
|
||||||
|
undefined:src/libxrpl/protocol/tokens.cpp
|
||||||
|
undefined:src/libxrpl/shamap/SHAMap.cpp
|
||||||
|
undefined:src/test/app/Batch_test.cpp
|
||||||
|
undefined:src/test/app/Invariants_test.cpp
|
||||||
|
undefined:src/test/app/NFToken_test.cpp
|
||||||
|
undefined:src/test/app/Offer_test.cpp
|
||||||
|
undefined:src/test/app/Path_test.cpp
|
||||||
|
undefined:src/test/basics/XRPAmount_test.cpp
|
||||||
|
undefined:src/test/beast/LexicalCast_test.cpp
|
||||||
|
undefined:src/test/jtx/impl/acctdelete.cpp
|
||||||
|
undefined:src/test/ledger/SkipList_test.cpp
|
||||||
|
undefined:src/test/rpc/Subscribe_test.cpp
|
||||||
|
undefined:src/tests/libxrpl/basics/RangeSet.cpp
|
||||||
|
undefined:src/xrpld/app/main/BasicApp.cpp
|
||||||
|
undefined:src/xrpld/app/main/BasicApp.cpp
|
||||||
|
undefined:src/xrpld/app/misc/detail/AmendmentTable.cpp
|
||||||
|
undefined:src/xrpld/app/misc/NetworkOPs.cpp
|
||||||
|
undefined:src/libxrpl/json/json_value.cpp
|
||||||
|
undefined:src/xrpld/app/paths/detail/StrandFlow.h
|
||||||
|
undefined:src/xrpld/app/tx/detail/NFTokenMint.cpp
|
||||||
|
undefined:src/xrpld/app/tx/detail/SetOracle.cpp
|
||||||
|
undefined:src/xrpld/core/detail/JobQueue.cpp
|
||||||
|
undefined:src/xrpld/core/detail/Workers.cpp
|
||||||
|
undefined:src/xrpld/rpc/detail/Role.cpp
|
||||||
|
undefined:src/xrpld/rpc/handlers/GetAggregatePrice.cpp
|
||||||
|
undefined:xrpl/basics/base_uint.h
|
||||||
|
undefined:xrpl/basics/DecayingSample.h
|
||||||
|
undefined:xrpl/beast/test/yield_to.h
|
||||||
|
undefined:xrpl/beast/xor_shift_engine.h
|
||||||
|
undefined:xrpl/nodestore/detail/varint.h
|
||||||
|
undefined:xrpl/peerfinder/detail/Counts.h
|
||||||
|
undefined:xrpl/protocol/nft.h
|
||||||
|
|
||||||
|
# basic_string.h:483:51: runtime error: unsigned integer overflow
|
||||||
|
unsigned-integer-overflow:basic_string.h
|
||||||
|
unsigned-integer-overflow:bits/chrono.h
|
||||||
|
unsigned-integer-overflow:bits/random.h
|
||||||
|
unsigned-integer-overflow:bits/random.tcc
|
||||||
|
unsigned-integer-overflow:bits/stl_algobase.h
|
||||||
|
unsigned-integer-overflow:bits/uniform_int_dist.h
|
||||||
|
unsigned-integer-overflow:string_view
|
||||||
|
|
||||||
|
# runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'std::size_t' (aka 'unsigned long')
|
||||||
|
unsigned-integer-overflow:src/libxrpl/basics/base64.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/basics/Number.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/crypto/RFC1751.cpp
|
||||||
|
unsigned-integer-overflow:rc/libxrpl/json/json_value.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/ledger/ApplyView.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/ledger/View.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/protocol/Permissions.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/protocol/STAmount.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/protocol/STPathSet.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/protocol/tokens.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/shamap/SHAMap.cpp
|
||||||
|
unsigned-integer-overflow:src/test/app/Batch_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/app/Invariants_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/app/NFToken_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/app/Offer_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/app/Path_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/basics/XRPAmount_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/beast/LexicalCast_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/jtx/impl/acctdelete.cpp
|
||||||
|
unsigned-integer-overflow:src/test/ledger/SkipList_test.cpp
|
||||||
|
unsigned-integer-overflow:src/test/rpc/Subscribe_test.cpp
|
||||||
|
unsigned-integer-overflow:src/tests/libxrpl/basics/RangeSet.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/app/main/BasicApp.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/app/misc/detail/AmendmentTable.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/app/misc/NetworkOPs.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/app/paths/detail/StrandFlow.h
|
||||||
|
unsigned-integer-overflow:src/xrpld/app/tx/detail/NFTokenMint.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/app/tx/detail/SetOracle.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/rpc/detail/Role.cpp
|
||||||
|
unsigned-integer-overflow:src/xrpld/rpc/handlers/GetAggregatePrice.cpp
|
||||||
|
unsigned-integer-overflow:xrpl/basics/base_uint.h
|
||||||
|
unsigned-integer-overflow:xrpl/basics/DecayingSample.h
|
||||||
|
unsigned-integer-overflow:xrpl/beast/test/yield_to.h
|
||||||
|
unsigned-integer-overflow:xrpl/beast/xor_shift_engine.h
|
||||||
|
unsigned-integer-overflow:xrpl/nodestore/detail/varint.h
|
||||||
|
unsigned-integer-overflow:xrpl/peerfinder/detail/Counts.h
|
||||||
|
unsigned-integer-overflow:xrpl/protocol/nft.h
|
||||||
|
|
||||||
|
# Rippled intentional overflows and operations
|
||||||
|
# STAmount uses intentional negation of INT64_MIN and overflow in arithmetic
|
||||||
|
signed-integer-overflow:src/libxrpl/protocol/STAmount.cpp
|
||||||
|
unsigned-integer-overflow:src/libxrpl/protocol/STAmount.cpp
|
||||||
|
|
||||||
|
# XRPAmount test intentional overflows
|
||||||
|
signed-integer-overflow:src/test/basics/XRPAmount_test.cpp
|
||||||
|
|
||||||
|
# Peerfinder intentional overflow in counter arithmetic
|
||||||
|
unsigned-integer-overflow:src/xrpld/peerfinder/detail/Counts.h
|
||||||
|
|
||||||
|
# Signed integer overflow suppressions
|
||||||
|
signed-integer-overflow:src/test/beast/LexicalCast_test.cpp
|
||||||
|
|
||||||
|
# External library suppressions
|
||||||
|
unsigned-integer-overflow:nudb/detail/xxhash.hpp
|
||||||
|
|
||||||
|
# Protobuf intentional overflows in hash functions
|
||||||
|
# Protobuf uses intentional unsigned overflow for hash computation (stringpiece.h:393)
|
||||||
|
unsigned-integer-overflow:google/protobuf/stubs/stringpiece.h
|
||||||
|
|
||||||
|
# gRPC intentional overflows
|
||||||
|
# gRPC uses intentional overflow in timer calculations
|
||||||
|
unsigned-integer-overflow:grpc
|
||||||
|
unsigned-integer-overflow:timer_manager.cc
|
||||||
|
|
||||||
|
# Standard library intentional overflows
|
||||||
|
# These are intentional overflows in random number generation and character conversion
|
||||||
|
unsigned-integer-overflow:__random/seed_seq.h
|
||||||
|
unsigned-integer-overflow:__charconv/traits.h
|
||||||
|
|
||||||
|
|
||||||
|
# Suppress errors in RocksDB
|
||||||
|
# RocksDB uses intentional unsigned integer overflows in hash functions and CRC calculations
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/util/xxhash.h
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/util/xxph3.h
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/util/hash.cc
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/util/crc32c.cc
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/util/crc32c.h
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/include/rocksdb/utilities/options_type.h
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/table/format.h
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/table/format.cc
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/table/block_based/block_based_table_builder.cc
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/table/block_based/reader_common.cc
|
||||||
|
unsigned-integer-overflow:rocks*/b/src/db/version_set.cc
|
||||||
|
|
||||||
|
# RocksDB misaligned loads (intentional for performance on ARM64)
|
||||||
|
alignment:rocks*/b/src/util/crc32c_arm64.cc
|
||||||
|
|
||||||
|
# nudb intentional overflows in hash functions
|
||||||
|
unsigned-integer-overflow:nudb/detail/xxhash.hpp
|
||||||
|
alignment:nudb/detail/xxhash.hpp
|
||||||
|
|
||||||
|
# Snappy compression library intentional overflows
|
||||||
|
unsigned-integer-overflow:snapp*/b/src/snappy.cc
|
||||||
|
|
||||||
|
# Abseil intentional overflows
|
||||||
|
unsigned-integer-overflow:abse*/b/src/absl/strings/numbers.cc
|
||||||
|
unsigned-integer-overflow:abse*/b/src/absl/strings/internal/cord_rep_flat.h
|
||||||
|
|
||||||
|
# Standard library intentional overflows in chrono duration arithmetic
|
||||||
|
unsigned-integer-overflow:__chrono/duration.h
|
||||||
|
|
||||||
|
# Suppress undefined errors in RocksDB and nudb
|
||||||
|
undefined:rocks.*/b/src/util/crc32c_arm64.cc
|
||||||
|
undefined:rocks.*/b/src/util/xxhash.h
|
||||||
|
undefined:nudb
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
|
||||||
#include <xrpl/basics/MallocTrim.h>
|
|
||||||
|
|
||||||
#include <boost/predef.h>
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
pid_t const cachedPid = ::getpid();
|
|
||||||
} // namespace
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
|
|
||||||
long
|
|
||||||
parseVmRSSkB(std::string const& status)
|
|
||||||
{
|
|
||||||
std::istringstream iss(status);
|
|
||||||
std::string line;
|
|
||||||
|
|
||||||
while (std::getline(iss, line))
|
|
||||||
{
|
|
||||||
// Allow leading spaces/tabs before the key.
|
|
||||||
auto const firstNonWs = line.find_first_not_of(" \t");
|
|
||||||
if (firstNonWs == std::string::npos)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
constexpr char key[] = "VmRSS:";
|
|
||||||
constexpr auto keyLen = sizeof(key) - 1;
|
|
||||||
|
|
||||||
// Require the line (after leading whitespace) to start with "VmRSS:".
|
|
||||||
// Check if we have enough characters and the substring matches.
|
|
||||||
if (firstNonWs + keyLen > line.size() ||
|
|
||||||
line.substr(firstNonWs, keyLen) != key)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Move past "VmRSS:" and any following whitespace.
|
|
||||||
auto pos = firstNonWs + keyLen;
|
|
||||||
while (pos < line.size() &&
|
|
||||||
std::isspace(static_cast<unsigned char>(line[pos])))
|
|
||||||
{
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
long value = -1;
|
|
||||||
if (std::sscanf(line.c_str() + pos, "%ld", &value) == 1)
|
|
||||||
return value;
|
|
||||||
|
|
||||||
// Found the key but couldn't parse a number.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No VmRSS line found.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __GLIBC__ && BOOST_OS_LINUX
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
MallocTrimReport
|
|
||||||
mallocTrim(
|
|
||||||
[[maybe_unused]] std::optional<std::string> const& tag,
|
|
||||||
beast::Journal journal)
|
|
||||||
{
|
|
||||||
MallocTrimReport report;
|
|
||||||
|
|
||||||
#if !(defined(__GLIBC__) && BOOST_OS_LINUX)
|
|
||||||
JLOG(journal.debug()) << "malloc_trim not supported on this platform";
|
|
||||||
#else
|
|
||||||
|
|
||||||
report.supported = true;
|
|
||||||
|
|
||||||
if (journal.debug())
|
|
||||||
{
|
|
||||||
auto readFile = [](std::string const& path) -> std::string {
|
|
||||||
std::ifstream ifs(path);
|
|
||||||
if (!ifs.is_open())
|
|
||||||
return {};
|
|
||||||
return std::string(
|
|
||||||
std::istreambuf_iterator<char>(ifs),
|
|
||||||
std::istreambuf_iterator<char>());
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string const tagStr = tag.value_or("default");
|
|
||||||
std::string const statusPath =
|
|
||||||
"/proc/" + std::to_string(cachedPid) + "/status";
|
|
||||||
|
|
||||||
auto const statusBefore = readFile(statusPath);
|
|
||||||
report.rssBeforeKB = detail::parseVmRSSkB(statusBefore);
|
|
||||||
|
|
||||||
report.trimResult = ::malloc_trim(0);
|
|
||||||
|
|
||||||
auto const statusAfter = readFile(statusPath);
|
|
||||||
report.rssAfterKB = detail::parseVmRSSkB(statusAfter);
|
|
||||||
|
|
||||||
JLOG(journal.debug())
|
|
||||||
<< "malloc_trim tag=" << tagStr << " result=" << report.trimResult
|
|
||||||
<< " rss_before=" << report.rssBeforeKB << "kB"
|
|
||||||
<< " rss_after=" << report.rssAfterKB << "kB"
|
|
||||||
<< " delta=" << report.deltaKB() << "kB";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
report.trimResult = ::malloc_trim(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ripple
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
#include <xrpl/basics/MallocTrim.h>
|
|
||||||
|
|
||||||
#include <boost/predef.h>
|
|
||||||
|
|
||||||
#include <doctest/doctest.h>
|
|
||||||
|
|
||||||
using namespace ripple;
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
namespace ripple::detail {
|
|
||||||
long
|
|
||||||
parseVmRSSkB(std::string const& status);
|
|
||||||
} // namespace ripple::detail
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST_CASE("MallocTrimReport structure")
|
|
||||||
{
|
|
||||||
// Test default construction
|
|
||||||
MallocTrimReport report;
|
|
||||||
CHECK(report.supported == false);
|
|
||||||
CHECK(report.trimResult == -1);
|
|
||||||
CHECK(report.rssBeforeKB == -1);
|
|
||||||
CHECK(report.rssAfterKB == -1);
|
|
||||||
CHECK(report.deltaKB() == 0);
|
|
||||||
|
|
||||||
// Test deltaKB calculation - memory freed
|
|
||||||
report.rssBeforeKB = 1000;
|
|
||||||
report.rssAfterKB = 800;
|
|
||||||
CHECK(report.deltaKB() == -200);
|
|
||||||
|
|
||||||
// Test deltaKB calculation - memory increased
|
|
||||||
report.rssBeforeKB = 500;
|
|
||||||
report.rssAfterKB = 600;
|
|
||||||
CHECK(report.deltaKB() == 100);
|
|
||||||
|
|
||||||
// Test deltaKB calculation - no change
|
|
||||||
report.rssBeforeKB = 1234;
|
|
||||||
report.rssAfterKB = 1234;
|
|
||||||
CHECK(report.deltaKB() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
TEST_CASE("parseVmRSSkB")
|
|
||||||
{
|
|
||||||
using ripple::detail::parseVmRSSkB;
|
|
||||||
|
|
||||||
// Test standard format
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS: 123456 kB\n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == 123456);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with multiple lines
|
|
||||||
{
|
|
||||||
std::string status =
|
|
||||||
"Name: rippled\n"
|
|
||||||
"VmPeak: 1234567 kB\n"
|
|
||||||
"VmSize: 1234567 kB\n"
|
|
||||||
"VmRSS: 987654 kB\n"
|
|
||||||
"VmData: 123456 kB\n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == 987654);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with minimal whitespace
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS: 42 kB";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with extra whitespace
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS: 999999 kB";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == 999999);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with tabs
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS:\t\t12345 kB";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
// Note: tabs are not explicitly handled as spaces, this documents
|
|
||||||
// current behavior
|
|
||||||
CHECK(result == 12345);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test zero value
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS: 0 kB\n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test missing VmRSS
|
|
||||||
{
|
|
||||||
std::string status =
|
|
||||||
"Name: rippled\n"
|
|
||||||
"VmPeak: 1234567 kB\n"
|
|
||||||
"VmSize: 1234567 kB\n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test empty string
|
|
||||||
{
|
|
||||||
std::string status = "";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test malformed data (VmRSS but no number)
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS: \n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
// sscanf should fail to parse and return -1 unchanged
|
|
||||||
CHECK(result == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test malformed data (VmRSS but invalid number)
|
|
||||||
{
|
|
||||||
std::string status = "VmRSS: abc kB\n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
// sscanf should fail and return -1 unchanged
|
|
||||||
CHECK(result == -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test partial match (should not match "NotVmRSS:")
|
|
||||||
{
|
|
||||||
std::string status = "NotVmRSS: 123456 kB\n";
|
|
||||||
long result = parseVmRSSkB(status);
|
|
||||||
CHECK(result == -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST_CASE("mallocTrim basic functionality")
|
|
||||||
{
|
|
||||||
beast::Journal journal{beast::Journal::getNullSink()};
|
|
||||||
|
|
||||||
// Test with no tag
|
|
||||||
{
|
|
||||||
MallocTrimReport report = mallocTrim(std::nullopt, journal);
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
// On Linux with glibc, should be supported
|
|
||||||
CHECK(report.supported == true);
|
|
||||||
// trimResult should be 0 or 1 (success indicators)
|
|
||||||
CHECK(report.trimResult >= 0);
|
|
||||||
#else
|
|
||||||
// On other platforms, should be unsupported
|
|
||||||
CHECK(report.supported == false);
|
|
||||||
CHECK(report.trimResult == -1);
|
|
||||||
CHECK(report.rssBeforeKB == -1);
|
|
||||||
CHECK(report.rssAfterKB == -1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test with tag
|
|
||||||
{
|
|
||||||
MallocTrimReport report =
|
|
||||||
mallocTrim(std::optional<std::string>("test_tag"), journal);
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
CHECK(report.supported == true);
|
|
||||||
CHECK(report.trimResult >= 0);
|
|
||||||
#else
|
|
||||||
CHECK(report.supported == false);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("mallocTrim with debug logging")
|
|
||||||
{
|
|
||||||
beast::Journal journal{beast::Journal::getNullSink()};
|
|
||||||
|
|
||||||
MallocTrimReport report =
|
|
||||||
mallocTrim(std::optional<std::string>("debug_test"), journal);
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
CHECK(report.supported == true);
|
|
||||||
// The function should complete without crashing
|
|
||||||
#else
|
|
||||||
CHECK(report.supported == false);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("mallocTrim repeated calls")
|
|
||||||
{
|
|
||||||
beast::Journal journal{beast::Journal::getNullSink()};
|
|
||||||
|
|
||||||
// Call malloc_trim multiple times to ensure it's safe
|
|
||||||
for (int i = 0; i < 5; ++i)
|
|
||||||
{
|
|
||||||
MallocTrimReport report = mallocTrim(
|
|
||||||
std::optional<std::string>("iteration_" + std::to_string(i)),
|
|
||||||
journal);
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && BOOST_OS_LINUX
|
|
||||||
CHECK(report.supported == true);
|
|
||||||
CHECK(report.trimResult >= 0);
|
|
||||||
#else
|
|
||||||
CHECK(report.supported == false);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,6 @@
|
|||||||
#include <xrpld/shamap/NodeFamily.h>
|
#include <xrpld/shamap/NodeFamily.h>
|
||||||
|
|
||||||
#include <xrpl/basics/ByteUtilities.h>
|
#include <xrpl/basics/ByteUtilities.h>
|
||||||
#include <xrpl/basics/MallocTrim.h>
|
|
||||||
#include <xrpl/basics/ResolverAsio.h>
|
#include <xrpl/basics/ResolverAsio.h>
|
||||||
#include <xrpl/basics/random.h>
|
#include <xrpl/basics/random.h>
|
||||||
#include <xrpl/beast/asio/io_latency_probe.h>
|
#include <xrpl/beast/asio/io_latency_probe.h>
|
||||||
@@ -1107,8 +1106,6 @@ public:
|
|||||||
<< "; size after: " << cachedSLEs_.size();
|
<< "; size after: " << cachedSLEs_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
mallocTrim(std::optional<std::string>("doSweep"), m_journal);
|
|
||||||
|
|
||||||
// Set timer to do another sweep later.
|
// Set timer to do another sweep later.
|
||||||
setSweepTimer();
|
setSweepTimer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
#include <xrpld/rpc/MPTokenIssuanceID.h>
|
||||||
#include <xrpld/rpc/ServerHandler.h>
|
#include <xrpld/rpc/ServerHandler.h>
|
||||||
|
|
||||||
#include <xrpl/basics/MallocTrim.h>
|
|
||||||
#include <xrpl/basics/UptimeClock.h>
|
#include <xrpl/basics/UptimeClock.h>
|
||||||
#include <xrpl/basics/mulDiv.h>
|
#include <xrpl/basics/mulDiv.h>
|
||||||
#include <xrpl/basics/safe_cast.h>
|
#include <xrpl/basics/safe_cast.h>
|
||||||
@@ -2547,14 +2546,10 @@ NetworkOPsImp::setMode(OperatingMode om)
|
|||||||
if (mMode == om)
|
if (mMode == om)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto const oldMode = mMode.load(std::memory_order_relaxed);
|
|
||||||
mMode = om;
|
mMode = om;
|
||||||
|
|
||||||
accounting_.mode(om);
|
accounting_.mode(om);
|
||||||
|
|
||||||
if (oldMode != OperatingMode::FULL && om == OperatingMode::FULL)
|
|
||||||
mallocTrim(std::optional<std::string>("SyncComplete"), m_journal);
|
|
||||||
|
|
||||||
JLOG(m_journal.info()) << "STATE->" << strOperatingMode();
|
JLOG(m_journal.info()) << "STATE->" << strOperatingMode();
|
||||||
pubServer();
|
pubServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
|
#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
|
||||||
#include <xrpld/core/ConfigSections.h>
|
#include <xrpld/core/ConfigSections.h>
|
||||||
|
|
||||||
#include <xrpl/basics/MallocTrim.h>
|
|
||||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||||
#include <xrpl/nodestore/Scheduler.h>
|
#include <xrpl/nodestore/Scheduler.h>
|
||||||
#include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
|
#include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
|
||||||
@@ -546,8 +545,6 @@ SHAMapStoreImp::clearCaches(LedgerIndex validatedSeq)
|
|||||||
{
|
{
|
||||||
ledgerMaster_->clearLedgerCachePrior(validatedSeq);
|
ledgerMaster_->clearLedgerCachePrior(validatedSeq);
|
||||||
fullBelowCache_->clear();
|
fullBelowCache_->clear();
|
||||||
|
|
||||||
mallocTrim(std::optional<std::string>("clearCaches"), journal_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -613,8 +610,6 @@ SHAMapStoreImp::clearPrior(LedgerIndex lastRotated)
|
|||||||
});
|
});
|
||||||
if (healthWait() == stopping)
|
if (healthWait() == stopping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mallocTrim(std::optional<std::string>("clearPrior"), journal_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapStoreImp::HealthResult
|
SHAMapStoreImp::HealthResult
|
||||||
|
|||||||
Reference in New Issue
Block a user