From 42d0e66318b186d25eeb215b40ce26115401ed8b Mon Sep 17 00:00:00 2001 From: Devin Matthews Date: Thu, 29 Sep 2022 17:38:02 -0500 Subject: [PATCH] Add AddressSanitizer (-fsanitize=address) option. (#669) Details: - Added support for AddressSanitizer (ASan), a compiler-integrated memory error detector. The option (disabled by default) enables compiling and linking with the -fsanitize=address flag supported by clang, gcc, and probably others. This flag is employed during compilation of all BLIS source files *except* for optimized kernels, which are exempted because ASan usually requires an extra register, which violates the constraints for many gemm microkernels. - Minor whitespace, comment, ordering, and configure help text updates. --- Makefile | 1 + build/config.mk.in | 3 +++ common.mk | 34 ++++++++++++++++++++------ configure | 61 ++++++++++++++++++++++++++++++++++------------ 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index 5c4a32b59a..04cdca4214 100644 --- a/Makefile +++ b/Makefile @@ -1161,6 +1161,7 @@ showconfig: check-env @echo "install includedir: $(INSTALL_INCDIR)" @echo "install sharedir: $(INSTALL_SHAREDIR)" @echo "debugging status: $(DEBUG_TYPE)" + @echo "enable AddressSanitizer? $(MK_ENABLE_ASAN)" @echo "enabled threading model(s): $(THREADING_MODEL)" @echo "enable BLAS API? $(MK_ENABLE_BLAS)" @echo "enable CBLAS API? $(MK_ENABLE_CBLAS)" diff --git a/build/config.mk.in b/build/config.mk.in index 849a7ccfa9..efb123366b 100644 --- a/build/config.mk.in +++ b/build/config.mk.in @@ -124,6 +124,9 @@ LDFLAGS_PRESET := @ldflags_preset@ # The level of debugging info to generate. DEBUG_TYPE := @debug_type@ +# Whether to compile and link the AddressSanitizer library. +MK_ENABLE_ASAN := @enable_asan@ + # Whether operating system support was requested via --enable-system. ENABLE_SYSTEM := @enable_system@ diff --git a/common.mk b/common.mk index 00b9f8ad3b..e69b977824 100644 --- a/common.mk +++ b/common.mk @@ -118,6 +118,7 @@ get-noopt-cxxflags-for = $(strip $(CFLAGS_PRESET) \ get-refinit-cflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ $(call get-noopt-cflags-for,$(1)) \ -DBLIS_CNAME=$(1) \ + $(BUILD_ASANFLAGS) \ $(BUILD_CPPFLAGS) \ $(BUILD_SYMFLAGS) \ -DBLIS_IN_REF_KERNEL=1 \ @@ -129,6 +130,7 @@ get-refkern-cflags-for = $(strip $(call load-var-for,CROPTFLAGS,$(1)) \ $(call get-noopt-cflags-for,$(1)) \ $(COMPSIMDFLAGS) \ -DBLIS_CNAME=$(1) \ + $(BUILD_ASANFLAGS) \ $(BUILD_CPPFLAGS) \ $(BUILD_SYMFLAGS) \ -DBLIS_IN_REF_KERNEL=1 \ @@ -137,12 +139,14 @@ get-refkern-cflags-for = $(strip $(call load-var-for,CROPTFLAGS,$(1)) \ get-config-cflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ $(call get-noopt-cflags-for,$(1)) \ + $(BUILD_ASANFLAGS) \ $(BUILD_CPPFLAGS) \ $(BUILD_SYMFLAGS) \ ) get-frame-cflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ $(call get-noopt-cflags-for,$(1)) \ + $(BUILD_ASANFLAGS) \ $(BUILD_CPPFLAGS) \ $(BUILD_SYMFLAGS) \ ) @@ -201,11 +205,14 @@ get-sandbox-cxxflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ # Define a separate function that will return appropriate flags for use by # applications that want to use the same basic flags as those used when BLIS # was compiled. (NOTE: This is the same as the $(get-frame-cflags-for ...) -# function, except that it omits two variables that contain flags exclusively -# for use when BLIS is being compiled/built: BUILD_CPPFLAGS, which contains a -# cpp macro that confirms that BLIS is being built; and BUILD_SYMFLAGS, which -# contains symbol export flags that are only needed when a shared library is -# being compiled/linked.) +# function, except that it omits a few variables that contain flags exclusively +# for use when BLIS is being compiled/built: +# - BUILD_CPPFLAGS, which contains a cpp macro that confirms that BLIS +# is being built; +# - BUILD_SYMFLAGS, which contains symbol export flags that are only +# needed when a shared library is being compiled/linked; and +# - BUILD_ASANFLAGS, which contains a flag that causes the compiler to +# insert instrumentation for memory error detection. get-user-cflags-for = $(strip $(call load-var-for,COPTFLAGS,$(1)) \ $(call get-noopt-cflags-for,$(1)) \ ) @@ -563,6 +570,11 @@ ifeq ($(DEBUG_TYPE),sde) LDFLAGS := $(filter-out $(LIBMEMKIND),$(LDFLAGS)) endif +# If AddressSanitizer is enabled, add the compiler flag to LDFLAGS. +ifeq ($(MK_ENABLE_ASAN),yes) +LDFLAGS += -fsanitize=address +endif + # Specify the shared library's 'soname' field. # NOTE: The flag for creating shared objects is different for Linux and OS X. ifeq ($(OS_NAME),Darwin) @@ -796,11 +808,19 @@ $(foreach c, $(CONFIG_LIST_FAM), $(eval $(call append-var-for,CXXLANGFLAGS,$(c)) CPPROCFLAGS := -D_POSIX_C_SOURCE=200112L $(foreach c, $(CONFIG_LIST_FAM), $(eval $(call append-var-for,CPPROCFLAGS,$(c)))) +# --- AddressSanitizer flags --- + +ifeq ($(MK_ENABLE_ASAN),yes) +BUILD_ASANFLAGS := -fsanitize=address +else +BUILD_ASANFLAGS := +endif + # --- Threading flags --- # NOTE: We don't have to explicitly omit -pthread when --disable-system is given -# since that option forces --enable-threading=none, and thus -pthread never gets -# added to begin with. +# since that option forces --enable-threading=single, and thus -pthread never +# gets added to begin with. CTHREADFLAGS := diff --git a/configure b/configure index 858ce55ded..a53f25380e 100755 --- a/configure +++ b/configure @@ -224,12 +224,22 @@ print_usage() echo " " echo " --enable-mem-tracing, --disable-mem-tracing" echo " " - echo " Enable (disable by default) output to stdout that traces" + echo " Enable (disabled by default) output to stdout that traces" echo " the allocation and freeing of memory, including the names" echo " of the functions that triggered the allocation/freeing." echo " Enabling this option WILL NEGATIVELY IMPACT PERFORMANCE." echo " Please use only for informational/debugging purposes." echo " " + echo " --enable-asan, --disable-asan" + echo " " + echo " Enable (disabled by default) compiling and linking BLIS" + echo " framework code with the AddressSanitizer (ASan) library." + echo " Optimized kernels are NOT compiled with ASan support due" + echo " to limitations of register assignment in inline assembly." + echo " WARNING: ENABLING THIS OPTION WILL NEGATIVELY IMPACT" + echo " PERFORMANCE. Please use only for informational/debugging" + echo " purposes." + echo " " echo " -i SIZE, --int-size=SIZE" echo " " echo " Set the size (in bits) of internal BLIS integers and" @@ -2451,6 +2461,9 @@ main() debug_type='' debug_flag='' + # A flag indicating whether AddressSanitizer should be used. + enable_asan='no' + # The system flag. enable_system='yes' @@ -2576,6 +2589,12 @@ main() disable-debug) debug_flag=0 ;; + enable-asan) + enable_asan='yes' + ;; + disable-asan) + enable_asan='no' + ;; enable-verbose-make) enable_verbose='yes' ;; @@ -3357,6 +3376,20 @@ main() echo "${script_name}: no preset LDFLAGS detected." fi + # Check if the verbose make flag was specified. + if [ "x${enable_verbose}" = "xyes" ]; then + echo "${script_name}: enabling verbose make output. (disable with 'make V=0'.)" + else + echo "${script_name}: disabling verbose make output. (enable with 'make V=1'.)" + fi + + # Check if the ARG_MAX hack was requested. + if [ "x${enable_arg_max_hack}" = "xyes" ]; then + echo "${script_name}: enabling ARG_MAX hack." + else + echo "${script_name}: disabling ARG_MAX hack." + fi + # Check if the debug flag was specified. if [ -n "${debug_flag}" ]; then if [ "x${debug_type}" = "xopt" ]; then @@ -3373,29 +3406,24 @@ main() echo "${script_name}: debug symbols disabled." fi - # Check if the verbose make flag was specified. - if [ "x${enable_verbose}" = "xyes" ]; then - echo "${script_name}: enabling verbose make output. (disable with 'make V=0'.)" + # Check if the AddressSanitizer flag was specified. + if [ "x${enable_asan}" = "xyes" ]; then + echo "${script_name}: enabling AddressSanitizer support (except for optimized kernels)." else - echo "${script_name}: disabling verbose make output. (enable with 'make V=1'.)" + enable_asan='no' + echo "${script_name}: AddressSanitizer support disabled." fi - # Check if the ARG_MAX hack was requested. - if [ "x${enable_arg_max_hack}" = "xyes" ]; then - echo "${script_name}: enabling ARG_MAX hack." - else - echo "${script_name}: disabling ARG_MAX hack." - fi - - enable_shared_01=1 # Check if the static lib flag was specified. if [ "x${enable_static}" = "xyes" -a "x${enable_shared}" = "xyes" ]; then echo "${script_name}: building BLIS as both static and shared libraries." + enable_shared_01=1 + elif [ "x${enable_static}" = "xno" -a "x${enable_shared}" = "xyes" ]; then + echo "${script_name}: building BLIS as a shared library (static library disabled)." + enable_shared_01=1 elif [ "x${enable_static}" = "xyes" -a "x${enable_shared}" = "xno" ]; then echo "${script_name}: building BLIS as a static library (shared library disabled)." enable_shared_01=0 - elif [ "x${enable_static}" = "xno" -a "x${enable_shared}" = "xyes" ]; then - echo "${script_name}: building BLIS as a shared library (static library disabled)." else echo "${script_name}: Both static and shared libraries were disabled." echo "${script_name}: *** Please enable one (or both) to continue." @@ -3917,7 +3945,7 @@ main() # Create a #define for the configuration family (config_name). uconf=$(echo ${config_name} | tr '[:lower:]' '[:upper:]') config_name_define="#define BLIS_FAMILY_${uconf}\n" - + # Create a list of #defines, one for each configuration in config_list. config_list_defines="" for conf in ${config_list}; do @@ -4012,6 +4040,7 @@ main() | sed -e "s/@libpthread@/${libpthread_esc}/g" \ | sed -e "s/@cflags_preset@/${cflags_preset_esc}/g" \ | sed -e "s/@ldflags_preset@/${ldflags_preset_esc}/g" \ + | sed -e "s/@enable_asan@/${enable_asan}/g" \ | sed -e "s/@debug_type@/${debug_type}/g" \ | sed -e "s/@enable_system@/${enable_system}/g" \ | sed -e "s/@threading_model@/${threading_model}/g" \