[m-rev.] for review: Support building with AddressSanitizer and UndefinedBehaviorSanitizer.
Peter Wang
novalazy at gmail.com
Tue Oct 11 16:15:50 AEDT 2016
configure.ac:
Add configure option --enable-sanitizers.
Mmake.common.in:
scripts/Mercury.config.in:
Add variables to be set when --enable-sanitizers is used.
scripts/mgnuc.in:
scripts/ml.in:
Pass sanitizer options to the C compiler and the linker.
compiler/options.m:
Add options --cflags-for-sanitizers and --linker-sanitizer-flags
for receiving the configuration.
Set --linker-trace-flags and --shlib-linker-trace-flags default
values to empty instead of "-g" (likely copy error).
compiler/compile_target_code.m:
Pass sanitizer options to the C compiler, and the linker when
building an executable or shared library.
runtime/Mmakefile:
trace/Mmakefile:
Pass sanitizer options to linker when building shared libraries.
README.sanitizers:
Add instructions.
---
Mmake.common.in | 4 ++++
README.sanitizers | 27 +++++++++++++++++++++++++++
compiler/compile_target_code.m | 7 +++++++
compiler/options.m | 14 +++++++++++---
configure.ac | 27 +++++++++++++++++++++++++++
runtime/Mmakefile | 8 ++++----
scripts/Mercury.config.in | 2 ++
scripts/mgnuc.in | 5 +++++
scripts/ml.in | 5 ++++-
trace/Mmakefile | 8 ++++----
10 files changed, 95 insertions(+), 12 deletions(-)
create mode 100644 README.sanitizers
diff --git a/Mmake.common.in b/Mmake.common.in
index 4a13ae9..1472d17 100644
--- a/Mmake.common.in
+++ b/Mmake.common.in
@@ -96,6 +96,10 @@ ifeq "$(findstring .par,$(GRADE))$(findstring .gc,$(GRADE))" ".par.gc"
ERROR_UNDEFINED = $(ALLOW_UNDEFINED)
endif
+# Specify any options required when linking if AddressSanitizer and other
+# sanitizers are enabled.
+LDFLAGS_FOR_SANITIZERS = @LDFLAGS_FOR_SANITIZERS@
+
# The following variables specify how to pass options to the $(CC) or
# $(LINK_SHARED_OBJ) command to specify directories to be searched at
# runtime for shared libraries.
diff --git a/README.sanitizers b/README.sanitizers
new file mode 100644
index 0000000..003c133
--- /dev/null
+++ b/README.sanitizers
@@ -0,0 +1,27 @@
+The configure option `--enable-sanitizers' will enable AddressSanitizer
+and UndefinedBehaviorSanitizer when building with gcc. The built Mercury
+compiler will also enable the same sanitizers when building user programs.
+
+AddressSanitizer and UndefinedBehaviorSanitizer are included in gcc 4.9
+and above. We have tested with gcc 5.8.0.
+
+Only high-level C grades work with the sanitizers enabled.
+
+For best results, add these options to Mmake.params before building Mercury:
+
+ EXTRA_MCFLAGS += --c-debug
+ EXTRA_MGNUCFLAGS += --c-debug
+ EXTRA_MLFLAGS += --c-debug
+
+Likewise, pass --c-debug when building user programs.
+
+clang does not work yet (tested version 3.8.0). It seemingly does not
+terminate when compiling certain files with UndefinedBehaviorSanitizer,
+e.g. runtime/mercury_deconstruct.c. There are also linking issues to be
+sorted out.
+
+Resources:
+
+ <http://clang.llvm.org/docs/AddressSanitizer.html>
+ <http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html>
+ <https://github.com/google/sanitizers/wiki/AddressSanitizer>
diff --git a/compiler/compile_target_code.m b/compiler/compile_target_code.m
index 8c56108..9c0895f 100644
--- a/compiler/compile_target_code.m
+++ b/compiler/compile_target_code.m
@@ -447,6 +447,8 @@ gather_c_compiler_flags(Globals, PIC, AllCFlags) :-
Target_Debug = no,
Target_DebugOpt = ""
),
+ globals.lookup_string_option(Globals, cflags_for_sanitizers,
+ SanitizerOpts),
globals.lookup_bool_option(Globals, use_trail, UseTrail),
(
UseTrail = yes,
@@ -573,6 +575,7 @@ gather_c_compiler_flags(Globals, PIC, AllCFlags) :-
CFLAGS_FOR_REGS, " ", CFLAGS_FOR_GOTOS, " ",
CFLAGS_FOR_THREADS, " ", CFLAGS_FOR_PIC, " ",
Target_DebugOpt,
+ SanitizerOpts, " ",
TypeLayoutOpt,
InlineAllocOpt,
AnsiOpt, " ",
@@ -1882,6 +1885,9 @@ link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType, ModuleName,
DebugOpts = ""
),
+ globals.lookup_string_option(Globals, linker_sanitizer_flags,
+ SanitizerOpts),
+
% Should the executable be statically linked?
globals.lookup_string_option(Globals, linkage, Linkage),
( if
@@ -2046,6 +2052,7 @@ link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType, ModuleName,
FrameworkDirectories, " ",
InstallNameOpt, " ",
DebugOpts, " ",
+ SanitizerOpts, " ",
Frameworks, " ",
ResCmdLinkOpts, " ",
LDFlags, " ",
diff --git a/compiler/options.m b/compiler/options.m
index f197f78..11512e0 100644
--- a/compiler/options.m
+++ b/compiler/options.m
@@ -827,6 +827,7 @@
; cflags_for_gotos
; cflags_for_threads
; cflags_for_debug
+ ; cflags_for_sanitizers
; cflags_for_pic
; c_flag_to_name_object_file
; object_file_extension
@@ -930,6 +931,7 @@
; shlib_linker_link_lib_suffix
; linker_debug_flags
; shlib_linker_debug_flags
+ ; linker_sanitizer_flags
; linker_trace_flags
; shlib_linker_trace_flags
; linker_path_flag
@@ -1700,6 +1702,7 @@ option_defaults_2(target_code_compilation_option, [
% The `mmc' script will override the
% default with values determined at
% configuration time.
+ cflags_for_sanitizers - string(""),
cflags_for_optimization - string("-O"),
cflags_for_ansi - string(""),
cflags_for_regs - string(""),
@@ -1812,8 +1815,9 @@ option_defaults_2(link_option, [
linker_opt_separator - string(""),
linker_debug_flags - string("-g"),
shlib_linker_debug_flags - string("-g"),
- linker_trace_flags - string("-g"),
- shlib_linker_trace_flags - string("-g"),
+ linker_sanitizer_flags - string(""),
+ linker_trace_flags - string(""),
+ shlib_linker_trace_flags - string(""),
linker_thread_flags - string(""),
shlib_linker_thread_flags - string(""),
linker_static_flags - string("-static"),
@@ -2676,6 +2680,7 @@ long_option("cflags-for-regs", cflags_for_regs).
long_option("cflags-for-gotos", cflags_for_gotos).
long_option("cflags-for-threads", cflags_for_threads).
long_option("cflags-for-debug", cflags_for_debug).
+long_option("cflags-for-sanitizers", cflags_for_sanitizers).
long_option("cflags-for-pic", cflags_for_pic).
long_option("c-flag-to-name-object-file", c_flag_to_name_object_file).
long_option("object-file-extension", object_file_extension).
@@ -2780,6 +2785,7 @@ long_option("readline-libs", readline_libs).
long_option("linker-opt-separator", linker_opt_separator).
long_option("linker-debug-flags", linker_debug_flags).
long_option("shlib-linker-debug-flags", shlib_linker_debug_flags).
+long_option("linker-sanitizer-flags", linker_sanitizer_flags).
long_option("linker-trace-flags", linker_trace_flags).
long_option("shlib-linker-trace-flags", shlib_linker_trace_flags).
long_option("linker-thread-flags", linker_thread_flags).
@@ -5494,7 +5500,8 @@ options_help_target_code_compilation -->
% The --cflags-for-regs, --cflags-for-gotos,
% --cflags-for-threads, --cflags-for-pic,
% --cflags-for-warnings, --cflags-for-ansi,
- % --cflags-for-optimization, --c-flag-to-name-object-file,
+ % --cflags-for-optimization, --cflags-for-sanitizers,
+ % --c-flag-to-name-object-file,
% --object-file-extension and --pic-object-file-extension
% options are reserved for use by the `mmc' script;
% they are deliberately not documented.
@@ -5711,6 +5718,7 @@ options_help_link -->
% --hwloc-libs, --hwloc-static-libs,
% --linker-opt-separator,
% --linker-debug-flags, --shlib-linker-debug-flags,
+ % --linker-sanitizer-flags,
% --linker-trace-flags, --shlib-linker-trace-flags,
% --linker-thread-flags, --shlib-linker-thread-flags,
% --linker-static-flags, --linker-strip-flag,
diff --git a/configure.ac b/configure.ac
index 18568ad..5b7916f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4758,6 +4758,33 @@ if test "$USE_DLLS" = "yes"; then
AC_DEFINE(MR_USE_DLLS)
fi
+#-----------------------------------------------------------------------------#
+#
+# Sanitizers
+#
+
+AC_ARG_ENABLE([sanitizers],
+ AC_HELP_STRING([--enable-sanitizers],
+ [enable AddressSanitizer and UndefinedBehaviorSanitizer]),
+ [ac_sanitizers="$enableval"], [ac_sanitizers=no])
+
+case "$C_COMPILER_TYPE" in
+ gcc*)
+ if test "$ac_sanitizers" = yes
+ then
+ CFLAGS_FOR_SANITIZERS="-fsanitize=address,undefined"
+ LDFLAGS_FOR_SANITIZERS="-fsanitize=address,undefined -pthread"
+ fi
+ ;;
+ *)
+ CFLAGS_FOR_SANITIZERS=
+ LDFLAGS_FOR_SANITIZERS=
+ ;;
+esac
+
+AC_SUBST(CFLAGS_FOR_SANITIZERS)
+AC_SUBST(LDFLAGS_FOR_SANITIZERS)
+
#-----------------------------------------------------------------------------#
if test "$BOOTSTRAP_MC" = ""; then
diff --git a/runtime/Mmakefile b/runtime/Mmakefile
index f10ed10..87a0e1b 100644
--- a/runtime/Mmakefile
+++ b/runtime/Mmakefile
@@ -366,19 +366,19 @@ lib$(RT_LIB_NAME)$(DLL_DEF_LIB).$A: $(OBJS)
$(RANLIB) $(RANLIBFLAGS) lib$(RT_LIB_NAME)$(DLL_DEF_LIB).$A
lib$(RT_LIB_NAME).so: $(PIC_OBJS)
- $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) \
+ $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) $(LDFLAGS_FOR_SANITIZERS) \
-o lib$(RT_LIB_NAME).so $(PIC_OBJS) \
$(SHLIB_RPATH_OPT)$(FINAL_INSTALL_MERC_GC_LIB_DIR) \
- $(ALL_LD_LIBFLAGS) $(LDLIBS) $(THREADLIBS) \
+ $(ALL_LD_LIBFLAGS) $(LDLIBS) $(THREADLIBS) \
$(SHARED_LIBS)
# For Darwin we should pass the -install_name option.
lib$(RT_LIB_NAME).dylib: $(PIC_OBJS)
- $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) \
+ $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) $(LDFLAGS_FOR_SANITIZERS) \
-o lib$(RT_LIB_NAME).dylib $(PIC_OBJS) \
-install_name \
$(FINAL_INSTALL_MERC_LIB_DIR)/lib$(RT_LIB_NAME).dylib \
- $(ALL_LD_LIBFLAGS) $(LDLIBS) $(THREADLIBS) \
+ $(ALL_LD_LIBFLAGS) $(LDLIBS) $(THREADLIBS) \
$(SHARED_LIBS)
endif
diff --git a/scripts/Mercury.config.in b/scripts/Mercury.config.in
index 011a5b5..a548856 100644
--- a/scripts/Mercury.config.in
+++ b/scripts/Mercury.config.in
@@ -68,6 +68,7 @@ DEFAULT_MCFLAGS=\
--cflags-for-warnings "@CFLAGS_FOR_WARNINGS@" \
--cflags-for-threads "@CFLAGS_FOR_THREADS@" \
--cflags-for-debug "@CFLAGS_FOR_DEBUG@" \
+ --cflags-for-sanitizers "@CFLAGS_FOR_SANITIZERS@" \
--cflags-for-regs "@CFLAGS_FOR_REGS@" \
--cflags-for-gotos "@CFLAGS_FOR_GOTOS@" \
--cflags-for-pic "@CFLAGS_FOR_PIC@" \
@@ -104,6 +105,7 @@ DEFAULT_MCFLAGS=\
--linker-strip-flag "@LD_STRIP_FLAG@" \
--linker-debug-flags "@LDFLAGS_FOR_DEBUG@" \
--shlib-linker-debug-flags "@LD_LIBFLAGS_FOR_DEBUG@" \
+ --linker-sanitizer-flags "@LDFLAGS_FOR_SANITIZERS@" \
--linker-link-lib-flag "@LINK_LIB@" \
--linker-link-lib-suffix "@LINK_LIB_SUFFIX@" \
--shlib-linker-link-lib-flag "@LINK_LIB@" \
diff --git a/scripts/mgnuc.in b/scripts/mgnuc.in
index fb555c1..2ee7f03 100644
--- a/scripts/mgnuc.in
+++ b/scripts/mgnuc.in
@@ -27,6 +27,7 @@ CFLAGS_FOR_GOTOS="@CFLAGS_FOR_GOTOS@"
CFLAGS_FOR_THREADS="@CFLAGS_FOR_THREADS@"
CFLAGS_FOR_NO_STRICT_ALIASING="@CFLAGS_FOR_NO_STRICT_ALIASING@"
CFLAGS_FOR_ANSI="@CFLAGS_FOR_ANSI@"
+CFLAGS_FOR_SANITIZERS="@CFLAGS_FOR_SANITIZERS@"
AS="@AS@"
BYTES_PER_WORD="@BYTES_PER_WORD@"
MKTEMP=@MKTEMP@
@@ -501,6 +502,9 @@ case $non_local_gotos in
false) ;;
esac
+# if sanitizers were enabled at configure time, add CFLAGS_FOR_SANITIZERS
+SANITIZER_OPTS="$CFLAGS_FOR_SANITIZERS"
+
#
# Special case hacks for particular architectures
# Any code here needs to be duplicated in ../configure.in.
@@ -646,6 +650,7 @@ ALL_CC_OPTS="$MERC_ALL_C_INCL_DIRS\
$RECORD_TERM_SIZE_OPTS\
$MINIMAL_MODEL_OPTS\
$PREGEN_SPF_OPTS\
+ $SANITIZER_OPTS\
$SPLIT_OPTS\
$THREAD_OPTS\
$THREADSCOPE_OPTS\
diff --git a/scripts/ml.in b/scripts/ml.in
index 03e496a..9f8cd26 100644
--- a/scripts/ml.in
+++ b/scripts/ml.in
@@ -53,6 +53,7 @@ THREAD_LIBS="@THREAD_LIBS@"
HWLOC_LIBS="@HWLOC_LIBS@"
HWLOC_STATIC_LIBS="@HWLOC_STATIC_LIBS@"
TRACE_BASE_LIBS_SYSTEM="@TRACE_BASE_LIBS_SYSTEM@"
+LDFLAGS_FOR_SANITIZERS="@LDFLAGS_FOR_SANITIZERS@"
TMPDIR=${TMPDIR=/tmp}
MATH_LIB=${MERCURY_MATH_LIB="@MATH_LIB@"}
@@ -426,6 +427,7 @@ case $make_shared_lib in
ARCH_OPTS="$ARCH_OPTS $LD_LIBFLAGS_FOR_TRACE"
;;
esac
+ SANITIZER_OPTS="$LDFLAGS_FOR_SANITIZERS"
;;
false)
LINKER="$CC"
@@ -438,6 +440,7 @@ case $make_shared_lib in
ARCH_OPTS="$ARCH_OPTS $LDFLAGS_FOR_TRACE"
;;
esac
+ SANITIZER_OPTS="$LDFLAGS_FOR_SANITIZERS"
;;
esac
@@ -556,7 +559,7 @@ else
NOLOGO_OPTS=""
fi
-LINKER_PRE_FLAGS="$NOLOGO_OPTS $MSVCRT_OPTS $PRINT_MAP_OPT $UNDEF_OPT $STRIP_OPTS $MAYBE_STATIC_OPT $ARCH_OPTS"
+LINKER_PRE_FLAGS="$NOLOGO_OPTS $MSVCRT_OPTS $PRINT_MAP_OPT $UNDEF_OPT $STRIP_OPTS $MAYBE_STATIC_OPT $ARCH_OPTS $SANITIZER_OPTS"
LINKER_POST_FLAGS="@LINK_OPT_SEP@ $NODEFAULTLIB_FLAG $DEBUG_FLAG $LIBDIR_OPTS $RPATH_OPT_LIST $LIBS"
case $verbose in
diff --git a/trace/Mmakefile b/trace/Mmakefile
index 81aad45..8eb07bf 100644
--- a/trace/Mmakefile
+++ b/trace/Mmakefile
@@ -272,7 +272,7 @@ lib$(EVENTSPEC_LIB_NAME)$(DLL_DEF_LIB).$A: $(EVENTSPEC_OBJS)
$(RANLIB) lib$(EVENTSPEC_LIB_NAME)$(DLL_DEF_LIB).$A
lib$(TRACE_LIB_NAME).so: $(TRACE_PIC_OBJS) lib$(EVENTSPEC_LIB_NAME).so
- $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) \
+ $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) $(LDFLAGS_FOR_SANITIZERS) \
-o lib$(TRACE_LIB_NAME).so $(TRACE_PIC_OBJS) \
$(RPATH_1)$(RPATH_2) \
$(ALL_LD_LIBFLAGS) $(TRACE_LDFLAGS) \
@@ -280,7 +280,7 @@ lib$(TRACE_LIB_NAME).so: $(TRACE_PIC_OBJS) lib$(EVENTSPEC_LIB_NAME).so
$(SHARED_LIBS)
lib$(EVENTSPEC_LIB_NAME).so: $(EVENTSPEC_PIC_OBJS)
- $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) \
+ $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) $(LDFLAGS_FOR_SANITIZERS) \
-o lib$(EVENTSPEC_LIB_NAME).so $(EVENTSPEC_PIC_OBJS) \
$(RPATH_1)$(RPATH_2) \
$(ALL_LD_LIBFLAGS) $(EVENTSPEC_LDFLAGS) \
@@ -289,7 +289,7 @@ lib$(EVENTSPEC_LIB_NAME).so: $(EVENTSPEC_PIC_OBJS)
# For Darwin:
lib$(TRACE_LIB_NAME).dylib: $(TRACE_PIC_OBJS) lib$(EVENTSPEC_LIB_NAME).dylib
- $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) \
+ $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) $(LDFLAGS_FOR_SANITIZERS) \
-o lib$(TRACE_LIB_NAME).dylib $(TRACE_PIC_OBJS) \
-install_name \
$(FINAL_INSTALL_MERC_LIB_DIR)/lib$(TRACE_LIB_NAME).dylib \
@@ -298,7 +298,7 @@ lib$(TRACE_LIB_NAME).dylib: $(TRACE_PIC_OBJS) lib$(EVENTSPEC_LIB_NAME).dylib
$(SHARED_LIBS)
lib$(EVENTSPEC_LIB_NAME).dylib: $(EVENTSPEC_PIC_OBJS)
- $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) \
+ $(LINK_SHARED_OBJ) $(ERROR_UNDEFINED) $(LDFLAGS_FOR_SANITIZERS) \
-o lib$(EVENTSPEC_LIB_NAME).dylib $(EVENTSPEC_PIC_OBJS) \
-install_name \
$(FINAL_INSTALL_MERC_LIB_DIR)/lib$(EVENTSPEC_LIB_NAME).dylib \
--
2.9.0
More information about the reviews
mailing list