Skip to content

Commit

Permalink
Merge pull request #4353 from pwojcikdev/ub-fixes-3
Browse files Browse the repository at this point in the history
UBSan workflow
  • Loading branch information
pwojcikdev authored Jan 8, 2024
2 parents eede334 + 4407ad7 commit 14db997
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 63 deletions.
16 changes: 11 additions & 5 deletions .github/workflows/code_sanitizers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,29 @@ on: [push, pull_request, workflow_dispatch]

jobs:
linux_sanitizers:
name: Linux [${{ matrix.SANITIZER }}] [${{ matrix.BACKEND }} | ${{ matrix.COMPILER }}]
name: Linux [${{ matrix.SANITIZER.name }}] [${{ matrix.BACKEND }} | ${{ matrix.COMPILER }}] ${{ matrix.SANITIZER.ignore_errors && ' (Errors Ignored)' || '' }}
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
BACKEND: [lmdb, rocksdb]
COMPILER: [clang]
SANITIZER: [ASAN, ASAN_INT, TSAN]
SANITIZER:
- { name: UBSAN, ignore_errors: false }
- { name: ASAN, ignore_errors: true }
- { name: ASAN_INT, ignore_errors: true }
- { name: TSAN, ignore_errors: true }
runs-on: ubuntu-22.04
env:
COMPILER: ${{ matrix.COMPILER }}
BACKEND: ${{ matrix.BACKEND }}
SANITIZER: ${{ matrix.SANITIZER }}
SANITIZER: ${{ matrix.SANITIZER.name }}
IGNORE_ERRORS: ${{ matrix.SANITIZER.ignore_errors }}
TEST_USE_ROCKSDB: ${{ matrix.BACKEND == 'rocksdb' && '1' || '0' }}
DEADLINE_SCALE_FACTOR: ${{ matrix.BACKEND == 'rocksdb' && '2' || '1' }}
ASAN_OPTIONS: log_exe_name=1:log_path=sanitizer_report
ASAN_OPTIONS: log_exe_name=1:log_path=sanitizer_report:suppressions=../asan_suppressions
TSAN_OPTIONS: log_exe_name=1:log_path=sanitizer_report:suppressions=../tsan_suppressions
UBSAN_OPTIONS: log_exe_name=1:log_path=sanitizer_report:print_stacktrace=1
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
steps:
- name: Checkout
Expand Down Expand Up @@ -49,6 +55,6 @@ jobs:

- name: Reports
if: steps.build.outcome == 'success' && (success() || failure())
continue-on-error: true
continue-on-error: ${{ env.IGNORE_ERRORS == 'true' }}
run: ../ci/tests/show-sanitizer-reports.sh
working-directory: build
131 changes: 82 additions & 49 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,6 @@ if(${NANO_ASIO_HANDLER_TRACKING} GREATER 0)
-DBOOST_ASIO_ENABLE_HANDLER_TRACKING)
endif()

option(NANO_ASAN_INT "Enable ASan+UBSan+Integer overflow" OFF)
option(NANO_ASAN "Enable ASan+UBSan" OFF)
option(NANO_TSAN "Enable TSan" OFF)
option(NANO_SIMD_OPTIMIZATIONS
"Enable CPU-specific SIMD optimizations (SSE/AVX or NEON, e.g.)" OFF)
option(
Expand Down Expand Up @@ -216,49 +213,99 @@ endif()

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set(USING_ASAN (NANO_ASAN OR RAIBLOCKS_ASAN))
set(USING_ASAN_INT (NANO_ASAN_INT OR RAIBLOCKS_ASAN_INT))
set(USING_TSAN (NANO_TSAN OR RAIBLOCKS_TSAN))

find_package(Threads)

if(WIN32)
find_library(PSAPI Psapi)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600 -DMINIUPNP_STATICLIB
-D_CRT_SECURE_NO_WARNINGS -DNOGDI /EHsc)
# Sanitizers
option(NANO_ASAN "Enable ASan" OFF)
if(NANO_ASAN)
if(MSVC)
message(FATAL_ERROR "ASan is not supported on MSVC")
endif()

message(STATUS "Using Asan")
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)

if(${USING_TSAN}
OR ${USING_ASAN}
OR ${USING_ASAN_INT})
message(WARNING "Cannot use TSAN or ASAN on Windows, sanitizers ignored")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_asan")
add_link_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_asan")
endif()

else()
if(NANO_WARN_TO_ERR)
add_compile_options(-Werror -Wno-deprecated-declarations)
add_definitions(-DED25519_NO_INLINE_ASM)
endif()

option(NANO_ASAN_INT "Enable ASan+Integer overflow" OFF)
if(NANO_ASAN_INT)
if(MSVC)
message(FATAL_ERROR "ASan+Integer overflow is not supported on MSVC")
endif()

if((${USING_TSAN} AND ${USING_ASAN}) OR (${USING_TSAN} AND ${USING_ASAN_INT}))
message(WARNING "Cannot use TSAN/ASAN together, defaulting to ASAN")
message(STATUS "Using ASan+Integer overflow")
add_compile_options(-fsanitize=address,integer)
add_link_options(-fsanitize=address,integer)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_asan")
add_link_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_asan")
endif()

if(${USING_ASAN} OR ${USING_ASAN_INT})
if(${USING_ASAN_INT})
add_compile_options(-fsanitize=address,undefined,integer)
else()
add_compile_options(-fsanitize=address,undefined)
endif()
add_definitions(-DED25519_NO_INLINE_ASM)
add_definitions(-DROCKSDB_UBSAN_RUN)
elseif(${USING_TSAN})
add_compile_options(-fsanitize=thread)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
"-fsanitize-blacklist=${PROJECT_SOURCE_DIR}/tsan_clang_blacklist")
endif()
add_definitions(-DED25519_NO_INLINE_ASM)
add_definitions(-DED25519_NO_INLINE_ASM)
endif()

option(NANO_UBSAN "Enable UBSan" OFF)
if(NANO_UBSAN)
if(MSVC)
message(FATAL_ERROR "UBSan is not supported on MSVC")
endif()

message(STATUS "Using UBSan")
add_compile_options(-fsanitize=undefined)
add_link_options(-fsanitize=undefined)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_ubsan")
add_link_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_ubsan")
endif()

add_definitions(-DED25519_NO_INLINE_ASM)
add_definitions(-DROCKSDB_UBSAN_RUN)
endif()

option(NANO_TSAN "Enable TSan" OFF)
if(NANO_TSAN)
if(MSVC)
message(FATAL_ERROR "TSan is not supported on MSVC")
endif()

message(STATUS "Using TSan")
add_compile_options(-fsanitize=thread)
add_link_options(-fsanitize=thread)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_tsan")
add_link_options(
"-fsanitize-ignorelist=${PROJECT_SOURCE_DIR}/sanitize_ignorelist_tsan")
endif()

add_definitions(-DED25519_NO_INLINE_ASM)
endif()

if(NANO_WARN_TO_ERR)
add_compile_options(-Werror -Wno-deprecated-declarations)
endif()

if(WIN32)
find_library(PSAPI Psapi)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600 -DMINIUPNP_STATICLIB
-D_CRT_SECURE_NO_WARNINGS -DNOGDI /EHsc)
else()
if(NANO_FUZZER_TEST)
add_compile_options(-fsanitize=fuzzer-no-link -fno-omit-frame-pointer)
add_definitions(-DNANO_FUZZER_TEST)
Expand Down Expand Up @@ -320,20 +367,6 @@ else()
set(PLATFORM_LINK_FLAGS "-static-libgcc -static-libstdc++")
endif()

if(${USING_ASAN_INT})
set(PLATFORM_LINK_FLAGS
"${PLATFORM_LINK_FLAGS} -fsanitize=address,undefined,integer")
elseif(${USING_ASAN})
set(PLATFORM_LINK_FLAGS
"${PLATFORM_LINK_FLAGS} -fsanitize=address,undefined")
elseif(${USING_TSAN})
set(PLATFORM_LINK_FLAGS "${PLATFORM_LINK_FLAGS} -fsanitize=thread")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PLATFORM_LINK_FLAGS
"${PLATFORM_LINK_FLAGS} -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/tsan_clang_blacklist"
)
endif()
endif()
if(NANO_FUZZER_TEST)
set(PLATFORM_LINK_FLAGS "${PLATFORM_LINK_FLAGS} -fsanitize=fuzzer-no-link")
endif()
Expand Down
Empty file added asan_suppressions
Empty file.
4 changes: 4 additions & 0 deletions ci/build.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/bash
set -euox pipefail
shopt -s nocasematch # Enable case-insensitive matching

BUILD_TARGET=""
if [[ ${1:-} ]]; then
Expand Down Expand Up @@ -35,6 +36,9 @@ if [[ ${SANITIZER:-} ]]; then
TSAN)
CMAKE_SANITIZER="-DNANO_TSAN=ON"
;;
UBSAN)
CMAKE_SANITIZER="-DNANO_UBSAN=ON"
;;
*)
echo "Unknown sanitizer: '${SANITIZER}'"
exit 1
Expand Down
7 changes: 5 additions & 2 deletions ci/prepare/linux/prepare-clang.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash
set -euo pipefail
set -euox pipefail

# Clang installer dependencies
DEBIAN_FRONTEND=noninteractive apt-get install -yqq lsb-release software-properties-common gnupg

CLANG_VERSION=16

Expand All @@ -12,4 +15,4 @@ update-alternatives --install /usr/bin/lldb lldb /usr/bin/lldb-$CLANG_VERSION 10

# Workaround to get a path that can be easily passed into cmake for BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
# See https://www.boost.org/doc/libs/1_70_0/doc/html/stacktrace/configuration_and_build.html#stacktrace.configuration_and_build.f3
backtrace_file=$(find /usr/lib/gcc/ -name 'backtrace.h' | head -n 1) && test -f $backtrace_file && ln -s $backtrace_file /tmp/backtrace.h
backtrace_file=$(find /usr/lib/gcc/ -name 'backtrace.h' | head -n 1) && test -f $backtrace_file && ln -s $backtrace_file /tmp/backtrace.h
2 changes: 1 addition & 1 deletion ci/prepare/linux/prepare-gcc.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/bash
set -euo pipefail
set -euox pipefail
3 changes: 2 additions & 1 deletion ci/prepare/linux/prepare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ COMPILER=${COMPILER:-gcc}
echo "Compiler: '${COMPILER}'"

# Common dependencies needed for building & testing
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get update -qq

DEBIAN_FRONTEND=noninteractive apt-get install -yqq \
build-essential \
g++ \
curl \
wget \
python3 \
zlib1g-dev \
Expand Down
10 changes: 5 additions & 5 deletions nano/test_common/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ std::shared_ptr<nano::node> nano::test::system::add_node (nano::node_config cons
(*j)->network.merge_peer ((*i)->network.endpoint ());

{
auto ec = poll_until_true (3s, [&node1, &node2, starting_size_1, starting_size_2] () {
auto ec = poll_until_true (5s, [&node1, &node2, starting_size_1, starting_size_2] () {
auto size_1 = node1->network.size ();
auto size_2 = node2->network.size ();
return size_1 > starting_size_1 && size_2 > starting_size_2;
Expand All @@ -87,7 +87,7 @@ std::shared_ptr<nano::node> nano::test::system::add_node (nano::node_config cons
{
{
// Wait for initial connection finish
auto ec = poll_until_true (3s, [&node1, &node2, starting_realtime_1, starting_realtime_2] () {
auto ec = poll_until_true (5s, [&node1, &node2, starting_realtime_1, starting_realtime_2] () {
auto realtime_1 = node1->tcp_listener.realtime_count.load ();
auto realtime_2 = node2->tcp_listener.realtime_count.load ();
return realtime_1 > starting_realtime_1 && realtime_2 > starting_realtime_2;
Expand All @@ -96,7 +96,7 @@ std::shared_ptr<nano::node> nano::test::system::add_node (nano::node_config cons
}
{
// Wait for keepalive message exchange
auto ec = poll_until_true (3s, [&node1, &node2, starting_keepalives_1, starting_keepalives_2] () {
auto ec = poll_until_true (5s, [&node1, &node2, starting_keepalives_1, starting_keepalives_2] () {
auto keepalives_1 = node1->stats.count (stat::type::message, stat::detail::keepalive, stat::dir::in);
auto keepalives_2 = node2->stats.count (stat::type::message, stat::detail::keepalive, stat::dir::in);
return keepalives_1 > starting_keepalives_1 && keepalives_2 > starting_keepalives_2;
Expand All @@ -108,15 +108,15 @@ std::shared_ptr<nano::node> nano::test::system::add_node (nano::node_config cons

{
// Ensure no bootstrap initiators are in progress
auto ec = poll_until_true (3s, [this, &begin] () {
auto ec = poll_until_true (5s, [this, &begin] () {
return std::all_of (begin, nodes.end (), [] (std::shared_ptr<nano::node> const & node_a) { return !node_a->bootstrap_initiator.in_progress (); });
});
debug_assert (!ec);
}
}
else
{
auto ec = poll_until_true (3s, [&node] () {
auto ec = poll_until_true (5s, [&node] () {
return !node->bootstrap_initiator.in_progress ();
});
debug_assert (!ec);
Expand Down
4 changes: 4 additions & 0 deletions sanitize_ignorelist
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
src:*crypto/ed25519*
src:*crypto/blake2*

src:*submodules/lmdb*
Empty file added sanitize_ignorelist_asan
Empty file.
Empty file added sanitize_ignorelist_tsan
Empty file.
Empty file added sanitize_ignorelist_ubsan
Empty file.

0 comments on commit 14db997

Please sign in to comment.