Skip to content

Commit

Permalink
Merge pull request #461 from prasannabhat/iox-#459-enable-ub-sanitizer
Browse files Browse the repository at this point in the history
iox-#459 enable UndefinedBehaviorSanitizer for iceoryx
  • Loading branch information
dkroenke authored Jan 8, 2021
2 parents 1463e48 + 2a5208d commit c0e7ed8
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/sanitize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Run tests
run: |
cd $GITHUB_WORKSPACE/build
../tools/run_all_tests.sh asan-only
../tools/run_all_tests.sh
# This job builds & runs iceoryx tests (with sanitizer) in macos-10.15
clang-sanitize-macos:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[![Gitter](https://badges.gitter.im/eclipse-iceoryx/iceoryx.svg)](https://gitter.im/eclipse/iceoryx)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Codecov](https://codecov.io/gh/eclipse-iceoryx/iceoryx/branch/master/graph/badge.svg?branch=master)](https://codecov.io/gh/eclipse-iceoryx/iceoryx?branch=master)

[![Sanitize](https://github.com/eclipse/iceoryx/workflows/Sanitize/badge.svg?branch=master)](https://github.com/eclipse/iceoryx/actions?query=workflow%3ASanitize)

## Introduction

Expand Down
9 changes: 9 additions & 0 deletions doc/website/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ If you want to execute only individual testcases then you can use these executab
Due to the fact that iceoryx works a lot with system memory it should be ensured that errors like memory leaks are not introduced.
To prevent these, we use the clang toolchain which offers several tools for scanning the codebase. One of them is the Adress-Sanitizer which checks for example on dangling pointers: [https://clang.llvm.org/docs/AddressSanitizer.html](https://clang.llvm.org/docs/AddressSanitizer.html)
In iceoryx below sanitizers are enabled at the moment.
- [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
AddressSanitizer is a fast memory error detector.
**NOTE :** AddressSanitizer exits on the first detected error, which means there could be more errors in the codebase when this error is reported.
- [LeakSanitizer](https://clang.llvm.org/docs/LeakSanitizer.html)
LeakSanitizer is a run-time memory leak detector. In iceoryx , it runs as part of the AdderssSanitizer.
- [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html)
UndefinedBehaviorSanitizer (UBSan) is a fast undefined behavior detector. Iceoryx uses default behaviour ie `print a verbose error report and continue execution`
In iceoryx are scripts available to do the scan on your own. Additionally the Scans are running on the CI in every Pull-Request.
As Requirement you should install the clang compiler:
```
Expand Down
52 changes: 33 additions & 19 deletions iceoryx_posh/test/moduletests/test_posh_runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,32 @@ class PoshRuntimeTestAccess : public PoshRuntime
{
public:
using PoshRuntime::factory_t;
/// @attention do not use the setRuntimeFactory in a test with a running RouDiEnvironment
using PoshRuntime::setRuntimeFactory;

PoshRuntimeTestAccess(iox::cxx::optional<const iox::ProcessName_t*> s)
: PoshRuntime(s)
{
}

static PoshRuntimeTestAccess*& getTestRuntime()
static PoshRuntime& getDefaultRuntime(iox::cxx::optional<const iox::ProcessName_t*> name)
{
static PoshRuntimeTestAccess* testRuntime = nullptr;
return testRuntime;
return PoshRuntime::defaultRuntimeFactory(name);
}

static void resetRuntimeFactory()
{
PoshRuntime::setRuntimeFactory(PoshRuntime::defaultRuntimeFactory);
}
};

namespace
{
bool callbackWasCalled = false;
PoshRuntime& testFactory(iox::cxx::optional<const iox::ProcessName_t*>)
PoshRuntime& testFactory(iox::cxx::optional<const iox::ProcessName_t*> name)
{
callbackWasCalled = true;
return *PoshRuntimeTestAccess::getTestRuntime();
return PoshRuntimeTestAccess::getDefaultRuntime(name);
}
} // namespace

Expand Down Expand Up @@ -428,20 +433,6 @@ TEST_F(PoshRuntime_test, CreateNodeReturnValue)
// EXPECT_EQ(nodeDeviceIdentifier, nodeData->m_nodeDeviceIdentifier);
}

TEST_F(PoshRuntime_test, SetValidRuntimeFactorySucceeds)
{
PoshRuntimeTestAccess::setRuntimeFactory(testFactory);
PoshRuntimeTestAccess::initRuntime("instance");

EXPECT_TRUE(callbackWasCalled);
}

TEST_F(PoshRuntime_test, SetEmptyRuntimeFactoryFails)
{
EXPECT_DEATH({ PoshRuntimeTestAccess::setRuntimeFactory(PoshRuntimeTestAccess::factory_t()); },
"Cannot set runtime factory. Passed factory must not be empty!");
}

TEST_F(PoshRuntime_test, OfferDefaultServiceDescriptionIsInvalid)
{
auto isServiceOffered = m_runtime->offerService(iox::capro::ServiceDescription());
Expand Down Expand Up @@ -475,3 +466,26 @@ TEST_F(PoshRuntime_test, FindServiceReturnsNoInstanceForDefaultDescription)

EXPECT_THAT(0u, instanceContainer.value().size());
}

// disabled because we cannot use the RouDiEnvironment but need a RouDi for this test
// will be re-enabled with the PoshRuntime Mock from #449
TEST(PoshRuntimeFactory_test, DISABLED_SetValidRuntimeFactorySucceeds)
{
// do not use the setRuntimeFactory in a test with a running RouDiEnvironment
PoshRuntimeTestAccess::setRuntimeFactory(testFactory);
PoshRuntimeTestAccess::initRuntime("instance");
PoshRuntimeTestAccess::resetRuntimeFactory();

EXPECT_TRUE(callbackWasCalled);
}

// disabled because we cannot use the RouDiEnvironment but need a RouDi for this test
// will be re-enabled with the PoshRuntime Mock from #449
TEST(PoshRuntimeFactory_test, DISABLED_SetEmptyRuntimeFactoryFails)
{
// do not use the setRuntimeFactory in a test with a running RouDiEnvironment
EXPECT_DEATH({ PoshRuntimeTestAccess::setRuntimeFactory(PoshRuntimeTestAccess::factory_t()); },
"Cannot set runtime factory. Passed factory must not be empty!");
// just in case the previous test doesn't die and breaks the following tests
PoshRuntimeTestAccess::resetRuntimeFactory();
}
11 changes: 8 additions & 3 deletions iceoryx_utils/cmake/IceoryxPlatform.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ endfunction()

if(SANITIZE)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(ICEORYX_SANITIZER_BLACKLIST_FILE ${CMAKE_BINARY_DIR}/sanitizer_blacklist/asan_compile_time.txt)
set(ICEORYX_SANITIZER_BLACKLIST_FILE ${CMAKE_BINARY_DIR}/sanitizer_blacklist/sanitizer_compile_time.txt)
iox_create_asan_compile_time_blacklist(${ICEORYX_SANITIZER_BLACKLIST_FILE})

set(ICEORYX_SANITIZER_BLACKLIST -fsanitize-blacklist=${ICEORYX_SANITIZER_BLACKLIST_FILE})
Expand All @@ -113,21 +113,26 @@ if(SANITIZE)

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(ICEORYX_SANITIZER_COMMON_FLAGS -fno-omit-frame-pointer -fno-optimize-sibling-calls)

# For using LeakSanitizer in standalone mode
# https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#stand-alone-mode
# Using this mode was a bit unstable
set(ICEORYX_LEAK_SANITIZER_FLAGS -fsanitize=leak)

set(ICEORYX_ADDRESS_SANITIZER_FLAGS -fsanitize=address -fsanitize-address-use-after-scope ${ICEORYX_SANITIZER_BLACKLIST})

# UndefinedBehaviorSanitizer
# -fno-sanitize-recover=... print a verbose error report and exit the program
set(ICEORYX_UB_SANITIZER_FLAGS -fsanitize=undefined -fno-sanitize-recover=undefined)

# Combine different sanitizer flags to define overall sanitization
set(ICEORYX_SANITIZER_FLAGS ${ICEORYX_SANITIZER_COMMON_FLAGS} ${ICEORYX_ADDRESS_SANITIZER_FLAGS} CACHE INTERNAL "")
set(ICEORYX_SANITIZER_FLAGS ${ICEORYX_SANITIZER_COMMON_FLAGS} ${ICEORYX_ADDRESS_SANITIZER_FLAGS} ${ICEORYX_UB_SANITIZER_FLAGS} CACHE INTERNAL "")

# unset local variables , to avoid polluting global space
unset(ICEORYX_SANITIZER_BLACKLIST)
unset(ICEORYX_SANITIZER_COMMON_FLAGS)
unset(ICEORYX_ADDRESS_SANITIZER_FLAGS)
unset(ICEORYX_UB_SANITIZER_FLAGS)
else()
message( FATAL_ERROR "You need to run sanitize with gcc/clang compiler." )
endif()
Expand Down
8 changes: 8 additions & 0 deletions tools/run_all_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,17 @@ set_sanitizer_options() {
export ASAN_OPTIONS
LSAN_OPTIONS=suppressions=$BASE_DIR/sanitizer_blacklist/lsan_runtime.txt
export LSAN_OPTIONS
UBSAN_OPTIONS=print_stacktrace=1
export UBSAN_OPTIONS

echo "ASAN_OPTIONS : $ASAN_OPTIONS"
echo "LSAN_OPTIONS : $LSAN_OPTIONS"
echo "UBSAN_OPTIONS : $UBSAN_OPTIONS"

if [[ ! -f $(which llvm-symbolizer) ]]
then
echo "WARNING : llvm-symbolizer not found. Stack trace may not be symbolized!"
fi
}

for arg in "$@"; do
Expand Down

0 comments on commit c0e7ed8

Please sign in to comment.