@@ -11,89 +11,112 @@ function(
11
11
ENABLE_SANITIZER_UNDEFINED_BEHAVIOR
12
12
ENABLE_SANITIZER_THREAD
13
13
ENABLE_SANITIZER_MEMORY
14
+ ENABLE_SANITIZER_POINTER_COMPARE
15
+ ENABLE_SANITIZER_POINTER_SUBTRACT
14
16
)
15
17
16
- if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang" )
17
- set (SANITIZERS "" )
18
-
19
- if (${ENABLE_SANITIZER_ADDRESS} )
20
- list (APPEND SANITIZERS "address" )
21
- if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8)
22
- list (APPEND SANITIZERS "pointer-compare" "pointer-subtract" )
23
- message (
24
- STATUS
25
- "To enable invalid pointer pairs detection, add detect_invalid_pointer_pairs=2 to the environment variable ASAN_OPTIONS."
26
- )
18
+ # check if the sanitizers are supported
19
+ check_sanitizers_support(
20
+ SUPPORTS_SANITIZER_ADDRESS
21
+ SUPPORTS_SANITIZER_UNDEFINED_BEHAVIOR
22
+ SUPPORTS_SANITIZER_LEAK
23
+ SUPPORTS_SANITIZER_THREAD
24
+ SUPPORTS_SANITIZER_MEMORY
25
+ SUPPORTS_SANITIZER_POINTER_COMPARE
26
+ SUPPORTS_SANITIZER_POINTER_SUBTRACT
27
+ )
28
+
29
+ # for each sanitizer, check if it is supported and enabled
30
+ set (SANITIZERS "" )
31
+ foreach (
32
+ SANITIZER IN
33
+ ITEMS "address"
34
+ "leak"
35
+ "undefined"
36
+ "thread"
37
+ "memory"
38
+ "pointer-compare"
39
+ "pointer-subtract"
40
+ )
41
+ if (${ENABLE_SANITIZER_${SANITIZER} })
42
+ if (${SUPPORTS_SANITIZER_${SANITIZER} })
43
+ list (APPEND SANITIZERS ${SANITIZER} )
44
+ else ()
45
+ # do not enable the sanitizer if it is not supported
46
+ message (STATUS "${SANITIZER} sanitizer is not supported. Not enabling it." )
27
47
endif ()
28
48
endif ()
49
+ endforeach ()
29
50
30
- if (${ENABLE_SANITIZER_LEAK} )
31
- list (APPEND SANITIZERS "leak" )
32
- endif ()
51
+ # Info on special cases
33
52
34
- if (${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR} )
35
- list (APPEND SANITIZERS "undefined" )
36
- endif ()
37
-
38
- if (${ENABLE_SANITIZER_THREAD} )
39
- if ("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS)
40
- message (WARNING "Thread sanitizer does not work with Address and Leak sanitizer enabled" )
41
- else ()
42
- list (APPEND SANITIZERS "thread" )
43
- endif ()
53
+ # Address sanitizer requires Leak sanitizer to be disabled
54
+ if (${ENABLE_SANITIZER_THREAD} AND "${SUPPORTS_SANITIZER_THREAD} " STREQUAL "ENABLE_SANITIZER_THREAD" )
55
+ if ("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS)
56
+ message (
57
+ WARNING
58
+ "Thread sanitizer does not work with Address or Leak sanitizer enabled. Disabling the thread sanitizer."
59
+ )
60
+ # remove thread sanitizer from the list
61
+ list (REMOVE_ITEM SANITIZERS "thread" )
44
62
endif ()
63
+ endif ()
45
64
46
- if (${ENABLE_SANITIZER_MEMORY} AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang" )
65
+ # Memory sanitizer requires all the code (including libc++) to be MSan-instrumented otherwise it reports false positives
66
+ if (${ENABLE_SANITIZER_MEMORY} AND "${SUPPORTS_SANITIZER_MEMORY} " STREQUAL "ENABLE_SANITIZER_MEMORY"
67
+ AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang"
68
+ )
69
+ message (
70
+ STATUS
71
+ "Memory sanitizer requires all the code (including libc++) to be MSan-instrumented otherwise it reports false positives"
72
+ )
73
+ if ("address" IN_LIST SANITIZERS OR "thread" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS)
47
74
message (
48
75
WARNING
49
- "Memory sanitizer requires all the code (including libc++) to be MSan-instrumented otherwise it reports false positives "
76
+ "Memory sanitizer does not work with Address, Thread and Leak sanitizer enabled. Disabling the memory sanitizer. "
50
77
)
51
- if ("address" IN_LIST SANITIZERS OR "thread" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS)
52
- message (WARNING "Memory sanitizer does not work with Address, Thread and Leak sanitizer enabled" )
53
- else ()
54
- list (APPEND SANITIZERS "memory" )
55
- endif ()
56
- endif ()
57
- elseif (MSVC )
58
- if (${ENABLE_SANITIZER_ADDRESS} )
59
- list (APPEND SANITIZERS "address" )
78
+ # remove memory sanitizer from the list
79
+ list (REMOVE_ITEM SANITIZERS "memory" )
60
80
endif ()
61
- if (${ENABLE_SANITIZER_LEAK}
62
- OR ${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR}
63
- OR ${ENABLE_SANITIZER_THREAD}
64
- OR ${ENABLE_SANITIZER_MEMORY}
81
+ endif ()
82
+
83
+ if ((${ENABLE_SANITIZER_POINTER_COMPARE} AND "${SUPPORTS_SANITIZER_POINTER_COMPARE} " STREQUAL
84
+ "ENABLE_SANITIZER_POINTER_COMPARE" )
85
+ OR (${ENABLE_SANITIZER_POINTER_SUBTRACT} AND "${SUPPORTS_SANITIZER_POINTER_SUBTRACT} " STREQUAL
86
+ "ENABLE_SANITIZER_POINTER_SUBTRACT" )
87
+ )
88
+ message (
89
+ STATUS
90
+ "To enable invalid pointer pairs detection, add detect_invalid_pointer_pairs=2 to the environment variable ASAN_OPTIONS."
65
91
)
66
- message (WARNING "MSVC only supports address sanitizer" )
67
- endif ()
68
92
endif ()
69
93
94
+ # Join the sanitizers
70
95
list (JOIN SANITIZERS "," LIST_OF_SANITIZERS)
71
96
72
- if (LIST_OF_SANITIZERS)
73
- if (NOT "${LIST_OF_SANITIZERS} " STREQUAL "" )
74
- if (NOT MSVC )
75
- target_compile_options (${_project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS} )
76
- target_link_options (${_project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS} )
77
- else ()
78
- string (FIND "$ENV{PATH} " "$ENV{VSINSTALLDIR} " index_of_vs_install_dir)
79
- if ("${index_of_vs_install_dir} " STREQUAL "-1" )
80
- message (
81
- SEND_ERROR
82
- "Using MSVC sanitizers requires setting the MSVC environment before building the project. Please manually open the MSVC command prompt and rebuild the project."
83
- )
84
- endif ()
85
- if (POLICY CMP0141)
86
- if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT} " STREQUAL "" OR "${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT} "
87
- STREQUAL "EditAndContinue"
88
- )
89
- set_target_properties (${_project_name} PROPERTIES MSVC_DEBUG_INFORMATION_FORMAT ProgramDatabase)
90
- endif ()
91
- else ()
92
- target_compile_options (${_project_name} INTERFACE /Zi)
97
+ if (LIST_OF_SANITIZERS AND NOT "${LIST_OF_SANITIZERS} " STREQUAL "" )
98
+ if (NOT MSVC )
99
+ target_compile_options (${_project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS} )
100
+ target_link_options (${_project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS} )
101
+ else ()
102
+ string (FIND "$ENV{PATH} " "$ENV{VSINSTALLDIR} " index_of_vs_install_dir)
103
+ if ("${index_of_vs_install_dir} " STREQUAL "-1" )
104
+ message (
105
+ SEND_ERROR
106
+ "Using MSVC sanitizers requires setting the MSVC environment before building the project. Please manually open the MSVC command prompt and rebuild the project."
107
+ )
108
+ endif ()
109
+ if (POLICY CMP0141)
110
+ if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT} " STREQUAL "" OR "${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT} "
111
+ STREQUAL "EditAndContinue"
112
+ )
113
+ set_target_properties (${_project_name} PROPERTIES MSVC_DEBUG_INFORMATION_FORMAT ProgramDatabase)
93
114
endif ()
94
- target_compile_options ( ${_project_name} INTERFACE /fsanitize= ${LIST_OF_SANITIZERS} /INCREMENTAL: NO )
95
- target_link_options (${_project_name} INTERFACE /INCREMENTAL: NO )
115
+ else ( )
116
+ target_compile_options (${_project_name} INTERFACE /Zi )
96
117
endif ()
118
+ target_compile_options (${_project_name} INTERFACE /fsanitize=${LIST_OF_SANITIZERS} /INCREMENTAL:NO )
119
+ target_link_options (${_project_name} INTERFACE /INCREMENTAL:NO )
97
120
endif ()
98
121
endif ()
99
122
@@ -104,7 +127,7 @@ endfunction()
104
127
``check_sanitizers_support``
105
128
===============
106
129
107
- Detect sanitizers support for compiler.
130
+ Detect sanitizers support for compiler. You don't need to call this function directly anymore.
108
131
109
132
Note that some sanitizers cannot be enabled together, and this function doesn't check that. You should decide which sanitizers to enable based on your needs.
110
133
@@ -115,6 +138,8 @@ Output variables:
115
138
- ``ENABLE_SANITIZER_LEAK``: Leak sanitizer is supported
116
139
- ``ENABLE_SANITIZER_THREAD``: Thread sanitizer is supported
117
140
- ``ENABLE_SANITIZER_MEMORY``: Memory sanitizer is supported
141
+ - ``ENABLE_SANITIZER_POINTER_COMPARE``: Pointer compare sanitizer is supported
142
+ - ``ENABLE_SANITIZER_POINTER_SUBTRACT``: Pointer subtract sanitizer is supported
118
143
119
144
120
145
.. code:: cmake
@@ -123,7 +148,9 @@ Output variables:
123
148
ENABLE_SANITIZER_UNDEFINED_BEHAVIOR
124
149
ENABLE_SANITIZER_LEAK
125
150
ENABLE_SANITIZER_THREAD
126
- ENABLE_SANITIZER_MEMORY)
151
+ ENABLE_SANITIZER_MEMORY
152
+ ENABLE_SANITIZER_POINTER_COMPARE
153
+ ENABLE_SANITIZER_POINTER_SUBTRACT)
127
154
128
155
# then pass the sanitizers (e.g. ${ENABLE_SANITIZER_ADDRESS}) to project_options(... ${ENABLE_SANITIZER_ADDRESS} ...)
129
156
@@ -135,9 +162,13 @@ function(
135
162
ENABLE_SANITIZER_LEAK
136
163
ENABLE_SANITIZER_THREAD
137
164
ENABLE_SANITIZER_MEMORY
165
+ ENABLE_SANITIZER_POINTER_COMPARE
166
+ ENABLE_SANITIZER_POINTER_SUBTRACT
138
167
)
139
- set (SANITIZERS "" )
140
- if (NOT "${CMAKE_SYSTEM_NAME} " STREQUAL "Windows" )
168
+ set (SUPPORTED_SANITIZERS "" )
169
+ if (NOT "${CMAKE_SYSTEM_NAME} " STREQUAL "Windows" AND (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
170
+ OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang" )
171
+ )
141
172
set (HAS_SANITIZER_SUPPORT ON )
142
173
143
174
# Disable gcc sanitizer on some macos according to https://github.com/orgs/Homebrew/discussions/3384#discussioncomment-6264292
@@ -154,39 +185,58 @@ function(
154
185
endif ()
155
186
156
187
if (HAS_SANITIZER_SUPPORT)
157
- list (APPEND SANITIZERS "address" )
158
- list (APPEND SANITIZERS "undefined" )
159
- list (APPEND SANITIZERS "leak" )
160
- list (APPEND SANITIZERS "thread" )
161
- list (APPEND SANITIZERS "memory" )
188
+ set (SUPPORTED_SANITIZERS "" )
189
+ foreach (
190
+ SANITIZER IN
191
+ ITEMS "address"
192
+ "undefined"
193
+ "leak"
194
+ "thread"
195
+ "memory"
196
+ "pointer-compare"
197
+ "pointer-subtract"
198
+ )
199
+ if ((SANITIZER STREQUAL "pointer-compare" OR SANITIZER STREQUAL "pointer-subtract" )
200
+ AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8)
201
+ )
202
+ # pointer-compare and pointer-subtract are supported only by GCC 8 and later
203
+ continue ()
204
+ endif ()
205
+
206
+ list (APPEND SUPPORTED_SANITIZERS ${SANITIZER} )
207
+ endforeach ()
162
208
endif ()
163
209
elseif (MSVC )
164
210
# or it is MSVC and has run vcvarsall
165
211
string (FIND "$ENV{PATH} " "$ENV{VSINSTALLDIR} " index_of_vs_install_dir)
166
212
if (NOT "${index_of_vs_install_dir} " STREQUAL "-1" )
167
- list (APPEND SANITIZERS "address" )
213
+ list (APPEND SUPPORTED_SANITIZERS "address" )
168
214
endif ()
169
215
endif ()
170
216
171
- list (JOIN SANITIZERS "," LIST_OF_SANITIZERS)
217
+ if (NOT SUPPORTED_SANITIZERS OR "${SUPPORTED_SANITIZERS} " STREQUAL "" )
218
+ message (STATUS "No sanitizer is supported for the current platform/compiler" )
219
+ return ()
220
+ endif ()
172
221
173
- if (LIST_OF_SANITIZERS)
174
- if (NOT "${LIST_OF_SANITIZERS} " STREQUAL "" )
175
- if ("address" IN_LIST SANITIZERS)
176
- set (${ENABLE_SANITIZER_ADDRESS} "ENABLE_SANITIZER_ADDRESS" PARENT_SCOPE)
177
- endif ()
178
- if ("undefined" IN_LIST SANITIZERS)
179
- set (${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR} "ENABLE_SANITIZER_UNDEFINED_BEHAVIOR" PARENT_SCOPE)
180
- endif ()
181
- if ("leak" IN_LIST SANITIZERS)
182
- set (${ENABLE_SANITIZER_LEAK} "ENABLE_SANITIZER_LEAK" PARENT_SCOPE)
183
- endif ()
184
- if ("thread" IN_LIST SANITIZERS)
185
- set (${ENABLE_SANITIZER_THREAD} "ENABLE_SANITIZER_THREAD" PARENT_SCOPE)
186
- endif ()
187
- if ("memory" IN_LIST SANITIZERS)
188
- set (${ENABLE_SANITIZER_MEMORY} "ENABLE_SANITIZER_MEMORY" PARENT_SCOPE)
189
- endif ()
222
+ # Set the output variables
223
+ foreach (
224
+ SANITIZER IN
225
+ ITEMS "address"
226
+ "undefined"
227
+ "leak"
228
+ "thread"
229
+ "memory"
230
+ "pointer-compare"
231
+ "pointer-subtract"
232
+ )
233
+ set (SANITIZER_UPPERCASE "${SANITIZER} " )
234
+ string (TOUPPER ${SANITIZER} SANITIZER_UPPERCASE)
235
+
236
+ if (${SANITIZER} IN_LIST SUPPORTED_SANITIZERS)
237
+ set (${ENABLE_SANITIZER_${SANITIZER_UPPERCASE} } "ENABLE_SANITIZER_${SANITIZER_UPPERCASE} " PARENT_SCOPE)
238
+ else ()
239
+ set (${ENABLE_SANITIZER_${SANITIZER_UPPERCASE} } "" PARENT_SCOPE)
190
240
endif ()
191
- endif ()
241
+ endforeach ()
192
242
endfunction ()
0 commit comments