Skip to content

Commit 5f054fd

Browse files
rlalikStableCoder
authored andcommitted
Allow combining multiple sanitizers in one build.
Each selected sanitizer is tested individually, and if test fails the configure step aborts. After that, all selected sanitizers are tested for mutual compatibility. It reuse SET_SANITIZER, sanitizers are passed as a string which is tested with MATCHES. No Delimeter is actually required.
1 parent 7eb72fb commit 5f054fd

File tree

1 file changed

+88
-25
lines changed

1 file changed

+88
-25
lines changed

sanitizers.cmake

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# License for the specific language governing permissions and limitations under
1414
# the License.
1515

16+
include(CheckCXXSourceCompiles)
17+
1618
set(USE_SANITIZER
1719
""
1820
CACHE
@@ -28,48 +30,109 @@ function(append value)
2830
endforeach(variable)
2931
endfunction()
3032

33+
function(test_san_flags return_var flags)
34+
set(QUIET_BACKUP ${CMAKE_REQUIRED_QUIET})
35+
set(CMAKE_REQUIRED_QUIET TRUE)
36+
unset(${return_var} CACHE)
37+
set(FLAGS_BACKUP ${CMAKE_REQUIRED_FLAGS})
38+
set(CMAKE_REQUIRED_FLAGS "${flags}")
39+
check_cxx_source_compiles("int main() { return 0; }" ${return_var})
40+
set(CMAKE_REQUIRED_FLAGS "${FLAGS_BACKUP}")
41+
set(CMAKE_REQUIRED_QUIET "${QUIET_BACKUP}")
42+
endfunction()
43+
3144
if(USE_SANITIZER)
3245
append("-fno-omit-frame-pointer" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
3346

47+
unset(SANITIZER_SELECTED_FLAGS)
48+
3449
if(UNIX)
3550

3651
if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
3752
append("-O1" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
3853
endif()
3954

40-
if(USE_SANITIZER MATCHES "([Aa]ddress);([Uu]ndefined)"
41-
OR USE_SANITIZER MATCHES "([Uu]ndefined);([Aa]ddress)")
42-
message(STATUS "Building with Address, Undefined sanitizers")
43-
append("-fsanitize=address,undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
44-
elseif(USE_SANITIZER MATCHES "([Aa]ddress)")
55+
if(USE_SANITIZER MATCHES "([Aa]ddress)")
4556
# Optional: -fno-optimize-sibling-calls -fsanitize-address-use-after-scope
46-
message(STATUS "Building with Address sanitizer")
47-
append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
48-
elseif(USE_SANITIZER MATCHES "([Mm]emory([Ww]ith[Oo]rigins)?)")
57+
message(STATUS "Testing with Address sanitizer")
58+
set(SANITIZER_ADDR_FLAG "-fsanitize=address")
59+
test_san_flags(SANITIZER_ADDR_AVAILABLE ${SANITIZER_ADDR_FLAG})
60+
if (SANITIZER_ADDR_AVAILABLE)
61+
message(STATUS " Building with Address sanitizer")
62+
append("${SANITIZER_ADDR_FLAG}" SANITIZER_SELECTED_FLAGS)
63+
else()
64+
message(FATAL_ERROR "Address sanitizer not available for ${CMAKE_CXX_COMPILER}")
65+
endif()
66+
endif()
67+
68+
if(USE_SANITIZER MATCHES "([Mm]emory([Ww]ith[Oo]rigins)?)")
4969
# Optional: -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2
50-
append("-fsanitize=memory" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
70+
set(SANITIZER_MEM_FLAG "-fsanitize=memory")
5171
if(USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)")
52-
message(STATUS "Building with MemoryWithOrigins sanitizer")
53-
append("-fsanitize-memory-track-origins" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
72+
message(STATUS "Testing with MemoryWithOrigins sanitizer")
73+
append("-fsanitize-memory-track-origins" SANITIZER_MEM_FLAG)
5474
else()
55-
message(STATUS "Building with Memory sanitizer")
75+
message(STATUS "Testing with Memory sanitizer")
5676
endif()
57-
elseif(USE_SANITIZER MATCHES "([Uu]ndefined)")
58-
message(STATUS "Building with Undefined sanitizer")
59-
append("-fsanitize=undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
77+
test_san_flags(SANITIZER_MEM_AVAILABLE ${SANITIZER_MEM_FLAG})
78+
if (SANITIZER_MEM_AVAILABLE)
79+
if(USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)")
80+
message(STATUS " Building with MemoryWithOrigins sanitizer")
81+
else()
82+
message(STATUS " Building with Memory sanitizer")
83+
endif()
84+
append("${SANITIZER_MEM_FLAG}" SANITIZER_SELECTED_FLAGS)
85+
else()
86+
message(FATAL_ERROR "Memory [With Origins] sanitizer not available for ${CMAKE_CXX_COMPILER}")
87+
endif()
88+
endif()
89+
90+
if(USE_SANITIZER MATCHES "([Uu]ndefined)")
91+
message(STATUS "Testing with Undefined Behaviour sanitizer")
92+
set(SANITIZER_UB_FLAG "-fsanitize=undefined")
6093
if(EXISTS "${BLACKLIST_FILE}")
61-
append("-fsanitize-blacklist=${BLACKLIST_FILE}" CMAKE_C_FLAGS
62-
CMAKE_CXX_FLAGS)
94+
append("-fsanitize-blacklist=${BLACKLIST_FILE}" SANITIZER_UB_FLAG)
95+
endif()
96+
test_san_flags(SANITIZER_UB_AVAILABLE ${SANITIZER_UB_FLAG})
97+
if (SANITIZER_UB_AVAILABLE)
98+
message(STATUS " Building with Undefined Behaviour sanitizer")
99+
append("${SANITIZER_UB_FLAG}" SANITIZER_SELECTED_FLAGS)
100+
else()
101+
message(FATAL_ERROR "Undefined Behaviour sanitizer not available for ${CMAKE_CXX_COMPILER}")
102+
endif()
103+
endif()
104+
105+
if(USE_SANITIZER MATCHES "([Tt]hread)")
106+
message(STATUS "Testing with Thread sanitizer")
107+
set(SANITIZER_THREAD_FLAG "-fsanitize=thread")
108+
test_san_flags(SANITIZER_THREAD_AVAILABLE ${SANITIZER_THREAD_FLAG})
109+
if (SANITIZER_THREAD_AVAILABLE)
110+
message(STATUS " Building with Thread sanitizer")
111+
append("${SANITIZER_THREAD_FLAG}" SANITIZER_SELECTED_FLAGS)
112+
else()
113+
message(FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}")
63114
endif()
64-
elseif(USE_SANITIZER MATCHES "([Tt]hread)")
65-
message(STATUS "Building with Thread sanitizer")
66-
append("-fsanitize=thread" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
67-
elseif(USE_SANITIZER MATCHES "([Ll]eak)")
68-
message(STATUS "Building with Leak sanitizer")
69-
append("-fsanitize=leak" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
115+
endif()
116+
117+
if(USE_SANITIZER MATCHES "([Ll]eak)")
118+
message(STATUS "Testing with Leak sanitizer")
119+
set(SANITIZER_LEAK_FLAG "-fsanitize=leak")
120+
test_san_flags(SANITIZER_LEAK_AVAILABLE ${SANITIZER_LEAK_FLAG})
121+
if (SANITIZER_LEAK_AVAILABLE)
122+
message(STATUS " Building with Leak sanitizer")
123+
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)
124+
else()
125+
message(FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}")
126+
endif()
127+
endif()
128+
129+
message(STATUS "Sanitizer flags: ${SANITIZER_SELECTED_FLAGS}")
130+
test_san_flags(SANITIZER_SELECTED_COMPATIBLE ${SANITIZER_SELECTED_FLAGS})
131+
if (SANITIZER_SELECTED_COMPATIBLE)
132+
message(STATUS " Building with ${SANITIZER_SELECTED_FLAGS}")
133+
append("${SANITIZER_SELECTED_FLAGS}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
70134
else()
71-
message(
72-
FATAL_ERROR "Unsupported value of USE_SANITIZER: ${USE_SANITIZER}")
135+
message(FATAL_ERROR " Sanitizer flags ${SANITIZER_SELECTED_FLAGS} are not compatible.")
73136
endif()
74137
elseif(MSVC)
75138
if(USE_SANITIZER MATCHES "([Aa]ddress)")

0 commit comments

Comments
 (0)