blob: c7c33ff38d858753f9f429a3b4aaca6d84163c24 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
# detect-sanitizer.cmake -- Detect supported compiler sanitizer flags
# Licensed under the Zlib license, see LICENSE.md for details
macro(add_common_sanitizer_flags)
if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
add_compile_options(-g3)
endif()
check_c_compiler_flag(-fno-omit-frame-pointer HAVE_NO_OMIT_FRAME_POINTER)
if(HAVE_NO_OMIT_FRAME_POINTER)
add_compile_options(-fno-omit-frame-pointer)
add_link_options(-fno-omit-frame-pointer)
endif()
check_c_compiler_flag(-fno-optimize-sibling-calls HAVE_NO_OPTIMIZE_SIBLING_CALLS)
if(HAVE_NO_OPTIMIZE_SIBLING_CALLS)
add_compile_options(-fno-optimize-sibling-calls)
add_link_options(-fno-optimize-sibling-calls)
endif()
endmacro()
macro(check_sanitizer_support known_checks supported_checks)
set(available_checks "")
# Build list of supported sanitizer flags by incrementally trying compilation with
# known sanitizer checks
foreach(check ${known_checks})
if(available_checks STREQUAL "")
set(compile_checks "${check}")
else()
set(compile_checks "${available_checks},${check}")
endif()
set(CMAKE_REQUIRED_FLAGS -fsanitize=${compile_checks})
check_c_source_compiles("int main() { return 0; }" HAVE_SANITIZER_${check}
FAIL_REGEX "not supported|unrecognized command|unknown option")
set(CMAKE_REQUIRED_FLAGS)
if(HAVE_SANITIZER_${check})
set(available_checks ${compile_checks})
endif()
endforeach()
set(${supported_checks} ${available_checks})
endmacro()
macro(add_address_sanitizer)
set(known_checks
address
pointer-compare
pointer-subtract
)
check_sanitizer_support("${known_checks}" supported_checks)
if(NOT ${supported_checks} STREQUAL "")
message(STATUS "Address sanitizer is enabled: ${supported_checks}")
if(NOT MSVC)
add_compile_options("-fsanitize=${supported_checks}")
add_link_options("-fsanitize=${supported_checks}")
else()
add_compile_options("/fsanitize=${supported_checks}" "/Zi")
# Note that the MSVC linker doesn't use /fsanitizer
endif()
add_common_sanitizer_flags()
else()
message(FATAL_ERROR "Address sanitizer is not supported")
endif()
if(CMAKE_CROSSCOMPILING_EMULATOR)
# Only check for leak sanitizer if not cross-compiling due to qemu crash
message(WARNING "Leak sanitizer is not supported when cross compiling")
else()
# Leak sanitizer requires address sanitizer
check_sanitizer_support("leak" supported_checks)
if(NOT ${supported_checks} STREQUAL "")
message(STATUS "Leak sanitizer is enabled: ${supported_checks}")
add_compile_options(-fsanitize=${supported_checks})
add_link_options(-fsanitize=${supported_checks})
add_common_sanitizer_flags()
else()
# The Microsoft C compiler doesn't support Leak detector,
# so don't make this an error that disables ASAN completely
message(STATUS "Leak sanitizer is not supported")
endif()
endif()
endmacro()
macro(add_memory_sanitizer)
check_sanitizer_support("memory" supported_checks)
if(NOT ${supported_checks} STREQUAL "")
message(STATUS "Memory sanitizer is enabled: ${supported_checks}")
add_compile_options(-fsanitize=${supported_checks})
add_link_options(-fsanitize=${supported_checks})
add_common_sanitizer_flags()
check_c_compiler_flag(-fsanitize-memory-track-origins HAVE_MEMORY_TRACK_ORIGINS)
if(HAVE_MEMORY_TRACK_ORIGINS)
add_compile_options(-fsanitize-memory-track-origins)
add_link_options(-fsanitize-memory-track-origins)
endif()
else()
message(FATAL_ERROR "Memory sanitizer is not supported")
endif()
endmacro()
macro(add_thread_sanitizer)
check_sanitizer_support("thread" supported_checks)
if(NOT ${supported_checks} STREQUAL "")
message(STATUS "Thread sanitizer is enabled: ${supported_checks}")
add_compile_options(-fsanitize=${supported_checks})
add_link_options(-fsanitize=${supported_checks})
add_common_sanitizer_flags()
else()
message(FATAL_ERROR "Thread sanitizer is not supported")
endif()
endmacro()
macro(add_undefined_sanitizer)
set(known_checks
alignment
array-bounds
bool
bounds
builtin
enum
float-cast-overflow
float-divide-by-zero
function
integer-divide-by-zero
local-bounds
null
nonnull-attribute
pointer-overflow
return
returns-nonnull-attribute
shift
shift-base
shift-exponent
signed-integer-overflow
undefined
vla-bound
vptr
)
# unsigned-integer-overflow and unsigned-shift-base are not enabled, as they are not undefined in C/C++
# Object size sanitizer has no effect at -O0 and produces compiler warning if enabled
if(NOT CMAKE_C_FLAGS MATCHES "-O0")
list(APPEND known_checks object-size)
endif()
check_sanitizer_support("${known_checks}" supported_checks)
if(NOT ${supported_checks} STREQUAL "")
message(STATUS "Undefined behavior sanitizer is enabled: ${supported_checks}")
add_compile_options(-fsanitize=${supported_checks})
add_link_options(-fsanitize=${supported_checks})
add_common_sanitizer_flags()
else()
message(FATAL_ERROR "Undefined behavior sanitizer is not supported")
endif()
endmacro()
|