Skip to content

Commit fc2051d

Browse files
authored
Merge pull request #28 from HasKha/gori/sanitizers
Added cmake support for address sanitizer, and fixed related issue
2 parents b1fba68 + a5c35bb commit fc2051d

File tree

3 files changed

+257
-4
lines changed

3 files changed

+257
-4
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ list(PREPEND CMAKE_MODULE_PATH
6262
"${CMAKE_CURRENT_LIST_DIR}/cmake/third_party"
6363
)
6464

65-
65+
include(sanitizers)
6666
if(NASOQ_WITH_EIGEN)
6767
include(eigen)
6868
endif()

cmake/third_party/sanitizers.cmake

+250
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
# Source: https://github.com/StableCoder/cmake-scripts
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Copyright (C) 2018-2022 by George Cave - gcave@stablecoder.ca
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
7+
# use this file except in compliance with the License. You may obtain a copy of
8+
# the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
# License for the specific language governing permissions and limitations under
16+
# the License.
17+
#
18+
# This file has been modified by Adobe.
19+
#
20+
# All modifications are Copyright 2020 Adobe.
21+
22+
include(CheckCXXSourceCompiles)
23+
24+
set(USE_SANITIZER
25+
""
26+
CACHE
27+
STRING
28+
"Compile with a sanitizer. Options are: Address, Memory, MemoryWithOrigins, Undefined, Thread, Leak, 'Address;Undefined', CFI"
29+
)
30+
31+
function(append value)
32+
foreach(variable ${ARGN})
33+
set(${variable}
34+
"${${variable}} ${value}"
35+
PARENT_SCOPE)
36+
endforeach(variable)
37+
endfunction()
38+
39+
function(append_quoteless value)
40+
foreach(variable ${ARGN})
41+
set(${variable}
42+
${${variable}} ${value}
43+
PARENT_SCOPE)
44+
endforeach(variable)
45+
endfunction()
46+
47+
function(test_san_flags return_var flags)
48+
set(QUIET_BACKUP ${CMAKE_REQUIRED_QUIET})
49+
set(CMAKE_REQUIRED_QUIET TRUE)
50+
unset(${return_var} CACHE)
51+
set(FLAGS_BACKUP ${CMAKE_REQUIRED_FLAGS})
52+
set(CMAKE_REQUIRED_FLAGS "${flags}")
53+
check_cxx_source_compiles("int main() { return 0; }" ${return_var})
54+
set(CMAKE_REQUIRED_FLAGS "${FLAGS_BACKUP}")
55+
set(CMAKE_REQUIRED_QUIET "${QUIET_BACKUP}")
56+
endfunction()
57+
58+
if(USE_SANITIZER)
59+
append("-fno-omit-frame-pointer" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
60+
61+
unset(SANITIZER_SELECTED_FLAGS)
62+
63+
if(UNIX)
64+
65+
if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
66+
append("-O1" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
67+
endif()
68+
69+
if(USE_SANITIZER MATCHES "([Aa]ddress)")
70+
# Optional: -fno-optimize-sibling-calls -fsanitize-address-use-after-scope
71+
message(STATUS "Testing with Address sanitizer")
72+
set(SANITIZER_ADDR_FLAG "-fsanitize=address")
73+
test_san_flags(SANITIZER_ADDR_AVAILABLE ${SANITIZER_ADDR_FLAG})
74+
if(SANITIZER_ADDR_AVAILABLE)
75+
message(STATUS " Building with Address sanitizer")
76+
append("${SANITIZER_ADDR_FLAG}" SANITIZER_SELECTED_FLAGS)
77+
78+
if(AFL)
79+
append_quoteless(AFL_USE_ASAN=1 CMAKE_C_COMPILER_LAUNCHER
80+
CMAKE_CXX_COMPILER_LAUNCHER)
81+
endif()
82+
else()
83+
message(
84+
FATAL_ERROR
85+
"Address sanitizer not available for ${CMAKE_CXX_COMPILER}")
86+
endif()
87+
endif()
88+
89+
if(USE_SANITIZER MATCHES "([Mm]emory([Ww]ith[Oo]rigins)?)")
90+
# Optional: -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2
91+
set(SANITIZER_MEM_FLAG "-fsanitize=memory")
92+
if(USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)")
93+
message(STATUS "Testing with MemoryWithOrigins sanitizer")
94+
append("-fsanitize-memory-track-origins" SANITIZER_MEM_FLAG)
95+
else()
96+
message(STATUS "Testing with Memory sanitizer")
97+
endif()
98+
test_san_flags(SANITIZER_MEM_AVAILABLE ${SANITIZER_MEM_FLAG})
99+
if(SANITIZER_MEM_AVAILABLE)
100+
if(USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)")
101+
message(STATUS " Building with MemoryWithOrigins sanitizer")
102+
else()
103+
message(STATUS " Building with Memory sanitizer")
104+
endif()
105+
append("${SANITIZER_MEM_FLAG}" SANITIZER_SELECTED_FLAGS)
106+
107+
if(AFL)
108+
append_quoteless(AFL_USE_MSAN=1 CMAKE_C_COMPILER_LAUNCHER
109+
CMAKE_CXX_COMPILER_LAUNCHER)
110+
endif()
111+
else()
112+
message(
113+
FATAL_ERROR
114+
"Memory [With Origins] sanitizer not available for ${CMAKE_CXX_COMPILER}"
115+
)
116+
endif()
117+
endif()
118+
119+
if(USE_SANITIZER MATCHES "([Uu]ndefined)")
120+
message(STATUS "Testing with Undefined Behaviour sanitizer")
121+
set(SANITIZER_UB_FLAG "-fsanitize=undefined")
122+
if(EXISTS "${BLACKLIST_FILE}")
123+
append("-fsanitize-blacklist=${BLACKLIST_FILE}" SANITIZER_UB_FLAG)
124+
endif()
125+
test_san_flags(SANITIZER_UB_AVAILABLE ${SANITIZER_UB_FLAG})
126+
if(SANITIZER_UB_AVAILABLE)
127+
message(STATUS " Building with Undefined Behaviour sanitizer")
128+
append("${SANITIZER_UB_FLAG}" SANITIZER_SELECTED_FLAGS)
129+
130+
if(AFL)
131+
append_quoteless(AFL_USE_UBSAN=1 CMAKE_C_COMPILER_LAUNCHER
132+
CMAKE_CXX_COMPILER_LAUNCHER)
133+
endif()
134+
else()
135+
message(
136+
FATAL_ERROR
137+
"Undefined Behaviour sanitizer not available for ${CMAKE_CXX_COMPILER}"
138+
)
139+
endif()
140+
endif()
141+
142+
if(USE_SANITIZER MATCHES "([Tt]hread)")
143+
message(STATUS "Testing with Thread sanitizer")
144+
set(SANITIZER_THREAD_FLAG "-fsanitize=thread")
145+
test_san_flags(SANITIZER_THREAD_AVAILABLE ${SANITIZER_THREAD_FLAG})
146+
if(SANITIZER_THREAD_AVAILABLE)
147+
message(STATUS " Building with Thread sanitizer")
148+
append("${SANITIZER_THREAD_FLAG}" SANITIZER_SELECTED_FLAGS)
149+
150+
if(AFL)
151+
append_quoteless(AFL_USE_TSAN=1 CMAKE_C_COMPILER_LAUNCHER
152+
CMAKE_CXX_COMPILER_LAUNCHER)
153+
endif()
154+
else()
155+
message(
156+
FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}"
157+
)
158+
endif()
159+
endif()
160+
161+
if(USE_SANITIZER MATCHES "([Ll]eak)")
162+
message(STATUS "Testing with Leak sanitizer")
163+
set(SANITIZER_LEAK_FLAG "-fsanitize=leak")
164+
test_san_flags(SANITIZER_LEAK_AVAILABLE ${SANITIZER_LEAK_FLAG})
165+
if(SANITIZER_LEAK_AVAILABLE)
166+
message(STATUS " Building with Leak sanitizer")
167+
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)
168+
169+
if(AFL)
170+
append_quoteless(AFL_USE_LSAN=1 CMAKE_C_COMPILER_LAUNCHER
171+
CMAKE_CXX_COMPILER_LAUNCHER)
172+
endif()
173+
else()
174+
message(
175+
FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}"
176+
)
177+
endif()
178+
endif()
179+
180+
if(USE_SANITIZER MATCHES "([Cc][Ff][Ii])")
181+
message(STATUS "Testing with Control Flow Integrity(CFI) sanitizer")
182+
set(SANITIZER_CFI_FLAG "-fsanitize=cfi")
183+
test_san_flags(SANITIZER_CFI_AVAILABLE ${SANITIZER_CFI_FLAG})
184+
if(SANITIZER_CFI_AVAILABLE)
185+
message(STATUS " Building with Control Flow Integrity(CFI) sanitizer")
186+
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)
187+
188+
if(AFL)
189+
append_quoteless(AFL_USE_CFISAN=1 CMAKE_C_COMPILER_LAUNCHER
190+
CMAKE_CXX_COMPILER_LAUNCHER)
191+
endif()
192+
else()
193+
message(
194+
FATAL_ERROR
195+
"Control Flow Integrity(CFI) sanitizer not available for ${CMAKE_CXX_COMPILER}"
196+
)
197+
endif()
198+
endif()
199+
200+
message(STATUS "Sanitizer flags: ${SANITIZER_SELECTED_FLAGS}")
201+
test_san_flags(SANITIZER_SELECTED_COMPATIBLE ${SANITIZER_SELECTED_FLAGS})
202+
if(SANITIZER_SELECTED_COMPATIBLE)
203+
message(STATUS " Building with ${SANITIZER_SELECTED_FLAGS}")
204+
append("${SANITIZER_SELECTED_FLAGS}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
205+
else()
206+
message(
207+
FATAL_ERROR
208+
" Sanitizer flags ${SANITIZER_SELECTED_FLAGS} are not compatible.")
209+
endif()
210+
elseif(MSVC)
211+
if(USE_SANITIZER MATCHES "([Aa]ddress)")
212+
message(STATUS "Building with Address sanitizer")
213+
214+
# To use AddressSanitizer you need to disable incompatible options. See details here:
215+
# https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170#ide-msbuild
216+
#
217+
# Please note that there are some issues with using it directly from the IDE, it may work better to
218+
# run the code from the command-line (and through `ctest` which enables the ASAN_SAVE_DUMPS env variable):
219+
# https://stackoverflow.com/questions/76781556/visual-studio-22-asan-failed-to-use-and-restart-external-symbolizer
220+
# https://developercommunity.visualstudio.com/t/Fail-to-use-and-restart-external-symbol/10222443?q=+Failed+to+use+and+restart+external+symbolizer
221+
append("/fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
222+
223+
# Disable incremental linking
224+
add_link_options(/INCREMENTAL:NO)
225+
226+
# Disable RTC flag
227+
foreach(flag_var
228+
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
229+
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
230+
string(REGEX REPLACE "/RTC[^ ]*" "" ${flag_var} "${${flag_var}}")
231+
endforeach(flag_var)
232+
233+
# Do not use program database for debug builds (since it requires incremental linking).
234+
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
235+
236+
if(AFL)
237+
append_quoteless(AFL_USE_ASAN=1 CMAKE_C_COMPILER_LAUNCHER
238+
CMAKE_CXX_COMPILER_LAUNCHER)
239+
endif()
240+
else()
241+
message(
242+
FATAL_ERROR
243+
"This sanitizer not yet supported in the MSVC environment: ${USE_SANITIZER}"
244+
)
245+
endif()
246+
else()
247+
message(FATAL_ERROR "USE_SANITIZER is not supported on this platform.")
248+
endif()
249+
250+
endif()

src/clapacke/clapacke_dsytrf.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ int LAPACKE_dsytrf(
4646
if('L' != uplo && 'U' != uplo) {
4747
return -2; // argument 2 has an illegal value
4848
}
49+
char uplo_s[2];
50+
uplo_s[0] = uplo;
51+
uplo_s[1] = '\0';
4952

5053
// helper function to transpose an array
5154
auto transpose_into = [](double* out_x_t, clapack_int ldx_t, const double* x, clapack_int ldx, clapack_int n, int matrix_layout, char uplo) {
@@ -75,7 +78,7 @@ int LAPACKE_dsytrf(
7578
clapack_int info = 0;
7679
clapack_int lwork = -1; // flag to query work size
7780
double work_d; // a length-1 array of working space, as far as `dsytrf_` is concerned
78-
dsytrf_(&uplo, &n, a, &lda, ipiv, &work_d, &lwork, &info);
81+
dsytrf_(uplo_s, &n, a, &lda, ipiv, &work_d, &lwork, &info);
7982
if(info < 0) {
8083
return info-1;
8184
} else {
@@ -97,7 +100,7 @@ int LAPACKE_dsytrf(
97100
// call CLAPACK function on the transposed array
98101
std::vector<double> a_t(lda_t * maximum<clapack_int>(1,n));
99102
transpose_into(a_t.data(), lda_t, a, lda, n, matrix_layout, uplo);
100-
dsytrf_(&uplo, &n, a_t.data(), &lda_t, ipiv, work.data(), &lwork, &info);
103+
dsytrf_(uplo_s, &n, a_t.data(), &lda_t, ipiv, work.data(), &lwork, &info);
101104
if(info < 0) return info-1;
102105
transpose_into(a, lda, a_t.data(), lda_t, n, LAPACK_COL_MAJOR, uplo);
103106
} else if(LAPACK_COL_MAJOR == matrix_layout) {
@@ -110,7 +113,7 @@ int LAPACKE_dsytrf(
110113
std::vector<double> work(lwork);
111114

112115
// call CLAPACK function
113-
dsytrf_(&uplo, &n, a, &lda, ipiv, work.data(), &lwork, &info);
116+
dsytrf_(uplo_s, &n, a, &lda, ipiv, work.data(), &lwork, &info);
114117
if(info < 0) return info-1;
115118
} else {
116119
return -1; // argument 1 has an illegal value

0 commit comments

Comments
 (0)