Skip to content

Commit f89bdbe

Browse files
authored
Merge pull request #121 from kswiecicki/add-sanitizers
Add sanitizers
2 parents 0c60544 + 77e6aaf commit f89bdbe

File tree

7 files changed

+151
-17
lines changed

7 files changed

+151
-17
lines changed

.github/workflows/basic.yml

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
pool_tracking: ['ON', 'OFF']
1818
shared_library: ['OFF']
1919
os_provider: ['ON']
20+
sanitizers: [{asan: 'OFF', ubsan: 'OFF', tsan: 'OFF'}]
2021
include:
2122
- os: 'ubuntu-20.04'
2223
build_type: Release
@@ -42,17 +43,34 @@ jobs:
4243
compiler: {c: gcc, cxx: g++}
4344
shared_library: 'OFF'
4445
os_provider: 'OFF'
46+
# TODO: Enable sanitizer checks with pool tracking enabled. There's
47+
# a leak reported by sanitizer in jemalloc pool implementation that
48+
# points to a tracker_value_t not being free'd.
49+
# TODO: Move jobs with sanitizer checks to a separate workflow file.
50+
- os: 'ubuntu-22.04'
51+
build_type: Debug
52+
compiler: {c: clang, cxx: clang++}
53+
pool_tracking: 'OFF'
54+
shared_library: 'OFF'
55+
# TSAN is mutually exclusive with other sanitizers
56+
sanitizers: [{asan: 'ON', ubsan: 'ON', tsan: 'OFF'}, {asan: 'OFF', ubsan: 'OFF', tsan: 'ON'}]
57+
- os: 'ubuntu-22.04'
58+
build_type: Debug
59+
compiler: {c: gcc, cxx: g++}
60+
pool_tracking: 'OFF'
61+
shared_library: 'OFF'
62+
sanitizers: [{asan: 'ON', ubsan: 'ON', tsan: 'OFF'}, {asan: 'OFF', ubsan: 'OFF', tsan: 'ON'}]
4563
runs-on: ${{matrix.os}}
4664

4765
steps:
4866
- name: Checkout
4967
uses: actions/checkout@v4
50-
68+
5169
- name: Install apt packages
5270
run: |
5371
sudo apt-get update
5472
sudo apt-get install -y clang cmake libnuma-dev libjemalloc-dev libtbb-dev
55-
73+
5674
- name: Install g++-7
5775
if: matrix.compiler.cxx == 'g++-7'
5876
run: |
@@ -74,11 +92,14 @@ jobs:
7492
-DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON
7593
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
7694
-DUMF_BUILD_LIBUMF_POOL_SCALABLE=ON
95+
-DUSE_ASAN=${{matrix.sanitizers.asan}}
96+
-DUSE_UBSAN=${{matrix.sanitizers.ubsan}}
97+
-DUSE_TSAN=${{matrix.sanitizers.tsan}}
7798
7899
- name: Build UMF
79100
run: |
80101
cmake --build ${{env.BUILD_DIR}} -j $(nproc)
81-
102+
82103
- name: Run tests
83104
working-directory: ${{env.BUILD_DIR}}
84105
run: |
@@ -102,6 +123,8 @@ jobs:
102123
compiler: [{c: cl, cxx: cl}]
103124
pool_tracking: ['ON', 'OFF']
104125
shared_library: ['OFF']
126+
# ASAN is the only available sanitizer on Windows
127+
sanitizers: [{asan: 'OFF'}]
105128
include:
106129
- os: 'windows-2022'
107130
build_type: Release
@@ -113,6 +136,19 @@ jobs:
113136
compiler: {c: cl, cxx: cl}
114137
pool_tracking: 'ON'
115138
shared_library: 'ON'
139+
- os: 'windows-2022'
140+
build_type: Debug
141+
compiler: {c: clang-cl, cxx: clang-cl}
142+
pool_tracking: 'OFF'
143+
shared_library: 'OFF'
144+
sanitizers: [{asan: 'ON'}]
145+
- os: 'windows-2022'
146+
build_type: Debug
147+
compiler: {c: cl, cxx: cl}
148+
pool_tracking: 'OFF'
149+
shared_library: 'OFF'
150+
sanitizers: [{asan: 'ON'}]
151+
116152
runs-on: ${{matrix.os}}
117153

118154
steps:
@@ -130,6 +166,7 @@ jobs:
130166
-DUMF_FORMAT_CODE_STYLE=OFF
131167
-DUMF_DEVELOPER_MODE=ON
132168
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
169+
-DUSE_ASAN=${{matrix.sanitizers.asan}}
133170
134171
- name: Build UMF
135172
run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $Env:NUMBER_OF_PROCESSORS

CMakeLists.txt

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ option(UMF_BUILD_BENCHMARKS "Build UMF benchmarks" OFF)
2626
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)
2727
option(UMF_DEVELOPER_MODE "Enable developer checks, treats warnings as errors" OFF)
2828
option(UMF_FORMAT_CODE_STYLE "Format UMF code with clang-format" OFF)
29+
option(USE_ASAN "Enable AddressSanitizer checks" OFF)
30+
option(USE_UBSAN "Enable UndefinedBehaviorSanitizer checks" OFF)
31+
option(USE_TSAN "Enable ThreadSanitizer checks" OFF)
32+
option(USE_MSAN "Enable MemorySanitizer checks" OFF)
2933

3034
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
3135
set(LINUX TRUE)
@@ -57,6 +61,21 @@ if(MSVC)
5761
set(CUSTOM_COMMAND_BINARY_DIR ${CUSTOM_COMMAND_BINARY_DIR}/$<CONFIG>)
5862
endif()
5963

64+
# Sanitizer flags
65+
if(USE_ASAN)
66+
add_sanitizer_flag(address)
67+
endif()
68+
if(USE_UBSAN)
69+
add_sanitizer_flag(undefined)
70+
endif()
71+
if(USE_TSAN)
72+
add_sanitizer_flag(thread)
73+
endif()
74+
if(USE_MSAN)
75+
message(WARNING "MemorySanitizer requires instrumented libraries to prevent reporting false-positives")
76+
add_sanitizer_flag(memory)
77+
endif()
78+
6079
# A header only library to specify include directories in transitive
6180
# dependencies.
6281
add_library(umf_headers INTERFACE)
@@ -94,7 +113,7 @@ endif()
94113
if(UMF_FORMAT_CODE_STYLE)
95114
find_program(CLANG_FORMAT NAMES clang-format-15 clang-format-15.0 clang-format)
96115

97-
if(CLANG_FORMAT)
116+
if(CLANG_FORMAT)
98117
get_program_version_major_minor(${CLANG_FORMAT} CLANG_FORMAT_VERSION)
99118
message(STATUS "Found clang-format: ${CLANG_FORMAT} (version: ${CLANG_FORMAT_VERSION})")
100119

@@ -105,7 +124,7 @@ if(UMF_FORMAT_CODE_STYLE)
105124
else()
106125
message(FATAL_ERROR "UMF_FORMAT_CODE_STYLE=ON, but clang-format not found (required version: ${CLANG_FORMAT_REQUIRED})")
107126
endif()
108-
127+
109128
# Obtain files for clang-format check
110129
set(format_glob)
111130
foreach(DIR IN ITEMS include src test benchmark)
@@ -123,11 +142,11 @@ if(UMF_FORMAT_CODE_STYLE)
123142
file(GLOB_RECURSE format_list ${format_glob})
124143

125144
message(STATUS "Adding clang-format-check and clang-format-apply make targets")
126-
145+
127146
add_custom_target(clang-format-check
128147
COMMAND ${CLANG_FORMAT}
129-
--style=file
130-
--dry-run
148+
--style=file
149+
--dry-run
131150
-Werror
132151
${format_list}
133152
COMMENT "Check files formatting using clang-format")
@@ -137,7 +156,7 @@ if(UMF_FORMAT_CODE_STYLE)
137156
--style=file
138157
--i
139158
${format_list}
140-
COMMENT "Format files using clang-format")
159+
COMMENT "Format files using clang-format")
141160
endif()
142161

143162
# Add license to the installation path

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The Unified Memory Framework (UMF) is a library for constructing allocators and
1313

1414
A UMF memory pool is a combination of a pool allocator and a memory provider. A memory provider is responsible for coarse-grained memory allocations and management of memory pages, while the pool allocator controls memory pooling and handles fine-grained memory allocations.
1515

16-
Pool allocator can leverage existing allocators (e.g. jemalloc or tbbmalloc) or be written from scratch.
16+
Pool allocator can leverage existing allocators (e.g. jemalloc or tbbmalloc) or be written from scratch.
1717

1818
UMF comes with predefined pool allocators (see include/pool) and providers (see include/provider). UMF can also work with user-defined pools and providers that implement a specific interface (see include/umf/memory_pool_ops.h and include/umf/memory_provider_ops.h)
1919

@@ -98,6 +98,22 @@ $ cd build
9898
$ cmake {path_to_source_dir}
9999
$ make
100100
```
101+
102+
### Sanitizers
103+
104+
List of sanitizers available on Linux:
105+
- AddressSanitizer
106+
- UndefinedBehaviorSanitizer
107+
- ThreadSanitizer
108+
- Is mutually exclusive with other sanitizers.
109+
- MemorySanitizer
110+
- Requires linking against MSan-instrumented libraries to prevent false positive reports. More information [here](https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo).
111+
112+
List of sanitizers available on Windows:
113+
- AddressSanitizer
114+
115+
Listed sanitizers can be enabled with appropriate [CMake options](#cmake-standard-options).
116+
101117
## Contributions
102118

103119
All code has to be formatted using clang-format. To check the formatting do:
@@ -131,3 +147,7 @@ List of options provided by CMake:
131147
| UMF_ENABLE_POOL_TRACKING | Build UMF with pool tracking | ON/OFF | ON |
132148
| UMF_DEVELOPER_MODE | Treat warnings as errors and enables additional checks | ON/OFF | OFF |
133149
| UMF_FORMAT_CODE_STYLE | Add clang-format-check and clang-format-apply targets to make | ON/OFF | OFF |
150+
| USE_ASAN | Enable AddressSanitizer checks | ON/OFF | OFF |
151+
| USE_UBSAN | Enable UndefinedBehaviorSanitizer checks | ON/OFF | OFF |
152+
| USE_TSAN | Enable ThreadSanitizer checks | ON/OFF | OFF |
153+
| USE_MSAN | Enable MemorySanitizer checks | ON/OFF | OFF |

cmake/helpers.cmake

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
# Copyright (C) 2023 Intel Corporation
1+
# Copyright (C) 2023-2024 Intel Corporation
22
# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
33
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
44

55
#
66
# helpers.cmake -- helper functions for top-level CMakeLists.txt
77
#
88

9+
# CMake modules that check whether the C/C++ compiler supports a given flag
10+
include(CheckCCompilerFlag)
11+
include(CheckCXXCompilerFlag)
12+
913
# Sets ${ret} to version of program specified by ${name} in major.minor format
1014
function(get_program_version_major_minor name ret)
1115
execute_process(COMMAND ${name} --version
@@ -104,3 +108,48 @@ function(add_umf_library)
104108
add_umf_target_compile_options(${ARG_NAME})
105109
add_umf_target_link_options(${ARG_NAME})
106110
endfunction()
111+
112+
# Add sanitizer ${flag}, if it is supported, for both C and C++ compiler
113+
macro(add_sanitizer_flag flag)
114+
# Save current 'CMAKE_REQUIRED_LIBRARIES' state and temporarily extend it with
115+
# '-fsanitize=${flag}'. It is required by CMake to check the compiler for
116+
# availability of provided sanitizer ${flag}.
117+
if(WINDOWS)
118+
set(SANITIZER_FLAG "/fsanitize=${flag}")
119+
set(SANITIZER_ARGS "")
120+
else()
121+
set(SANITIZER_FLAG "-fsanitize=${flag}")
122+
set(SANITIZER_ARGS "-fno-sanitize-recover=all")
123+
endif()
124+
125+
set(SAVED_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
126+
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${SANITIZER_FLAG}")
127+
128+
if(${flag} STREQUAL "address")
129+
set(check_name "HAS_ASAN")
130+
elseif(${flag} STREQUAL "undefined")
131+
set(check_name "HAS_UBSAN")
132+
elseif(${flag} STREQUAL "thread")
133+
set(check_name "HAS_TSAN")
134+
elseif(${flag} STREQUAL "memory")
135+
set(check_name "HAS_MSAN")
136+
endif()
137+
138+
# Check C and CXX compilers for given sanitizer flag.
139+
check_c_compiler_flag("${SANITIZER_FLAG}" "C_${check_name}")
140+
check_cxx_compiler_flag("${SANITIZER_FLAG}" "CXX_${check_name}")
141+
if (${C_${check_name}} OR ${CXX_${check_name}})
142+
# Set appropriate linker flags for building executables.
143+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAG} ${SANITIZER_ARGS}")
144+
if (${C_${check_name}})
145+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_FLAG} ${SANITIZER_ARGS}")
146+
endif()
147+
if (${CXX_${check_name}})
148+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_FLAG} ${SANITIZER_ARGS}")
149+
endif()
150+
else()
151+
message(FATAL_ERROR "${flag} sanitizer is not supported (neither by C nor CXX compiler)")
152+
endif()
153+
154+
set(CMAKE_REQUIRED_LIBRARIES ${SAVED_CMAKE_REQUIRED_LIBRARIES})
155+
endmacro()

src/critnib/critnib.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2023 Intel Corporation
3+
* Copyright (C) 2023-2024 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -715,8 +715,8 @@ int critnib_find(struct critnib *c, uintptr_t key, enum find_dir_t dir,
715715
uintptr_t *rkey, void **rvalue) {
716716
uint64_t wrs1, wrs2;
717717
struct critnib_leaf *k;
718-
uintptr_t _rkey;
719-
void **_rvalue;
718+
uintptr_t _rkey = (uintptr_t)0x0;
719+
void **_rvalue = NULL;
720720

721721
/* <42 ≡ ≤41 */
722722
if (dir < -1) {

test/common/provider.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2023 Intel Corporation
3+
* Copyright (C) 2023-2024 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -17,6 +17,7 @@
1717

1818
#include "base.hpp"
1919
#include "cpp_helpers.hpp"
20+
#include "test_helpers.h"
2021

2122
namespace umf_test {
2223

@@ -68,10 +69,16 @@ struct provider_malloc : public provider_base_t {
6869
align = 8;
6970
}
7071

72+
// aligned_malloc returns a valid pointer despite not meeting the
73+
// requirement of 'size' being multiple of 'align' even though the
74+
// documentation says that it has to. AddressSanitizer returns an
75+
// error because of this issue.
76+
size_t aligned_size = ALIGN_UP(size, align);
77+
7178
#ifdef _WIN32
72-
*ptr = _aligned_malloc(size, align);
79+
*ptr = _aligned_malloc(aligned_size, align);
7380
#else
74-
*ptr = ::aligned_alloc(align, size);
81+
*ptr = ::aligned_alloc(align, aligned_size);
7582
#endif
7683

7784
return (*ptr) ? UMF_RESULT_SUCCESS

test/common/test_helpers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ static inline void UT_OUT(const char *format, ...) {
6969
(unsigned long long)(rhs)), \
7070
0)))
7171

72+
#define ALIGN_UP(size, align) (((size) + (align)-1) & ~((align)-1))
73+
7274
int bufferIsFilledWithChar(void *ptr, size_t size, char c);
7375

7476
int buffersHaveSameContent(void *first, void *second, size_t size);

0 commit comments

Comments
 (0)