Add support for clang Memory Sanitizer [1], which detects the usage of
uninitialized values. While elfutils itself is already checked with
valgrind, checking code that depends on elfutils requires elfutils to
be built with MSan.
MSan is not linked into shared libraries, and is linked into
executables statically. Therefore, unlike the other sanitizers, MSan
needs to be configured fairly early, since we need to drop
-D_FORTIFY_SOURCE [2], -Wl,-z,defs and --no-undefined.
Disable a few tests that run for more than 5 minutes due to test files
being statically linked with MSan.
[1] https://clang.llvm.org/docs/MemorySanitizer.html
[2] https://github.com/google/sanitizers/issues/247
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
configure.ac | 24 ++++++++++++++++++++++++
debuginfod/Makefile.am | 3 ++-
libasm/Makefile.am | 3 ++-
libdw/Makefile.am | 3 ++-
libelf/Makefile.am | 3 ++-
tests/Makefile.am | 10 +++++++++-
tests/run-readelf-self.sh | 5 +++++
tests/run-strip-reloc.sh | 5 +++++
tests/run-varlocs-self.sh | 5 +++++
9 files changed, 56 insertions(+), 5 deletions(-)
@@ -155,6 +155,29 @@ AC_SUBST([fpie_CFLAGS])
dso_LDFLAGS="-shared"
+NO_UNDEFINED=-Wl,--no-undefined
+AC_ARG_ENABLE([sanitize-memory],
+ AS_HELP_STRING([--enable-sanitize-memory],
+ [Use clang memory sanitizer]),
+ [use_msan=$enableval], [use_msan=no])
+if test "$use_msan" = yes; then
+ old_CFLAGS="$CFLAGS"
+ old_CXXFLAGS="$CXXFLAGS"
+ old_LDFLAGS="$LDFLAGS"
+ # -fsanitize=memory is not compatible with -D_FORTIFY_SOURCE, -Wl,-z,defs and --no-undefined
+ CFLAGS="$CFLAGS -fsanitize=memory -fsanitize-memory-track-origins -D_FORTIFY_SOURCE=0"
+ CXXFLAGS="$CXXFLAGS -fsanitize=memory -fsanitize-memory-track-origins -D_FORTIFY_SOURCE=0"
+ LDFLAGS="-shared"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([int main (int argc, char **argv) { return 0; }])], use_msan=yes, use_msan=no)
+ AS_IF([test "x$use_msan" == xyes],
+ ac_cv_zdefs=no NO_UNDEFINED=,
+ AC_MSG_WARN([clang memory sanitizer not available])
+ CFLAGS="$old_CFLAGS" CXXFLAGS="$old_CXXFLAGS")
+ LDFLAGS="$old_LDFLAGS"
+fi
+AC_SUBST(NO_UNDEFINED)
+AM_CONDITIONAL(USE_MEMORY_SANITIZER, test "$use_msan" = yes)
+
ZDEFS_LDFLAGS="-Wl,-z,defs"
AC_CACHE_CHECK([whether gcc supports $ZDEFS_LDFLAGS], ac_cv_zdefs, [dnl
save_LDFLAGS="$LDFLAGS"
@@ -887,6 +910,7 @@ AC_MSG_NOTICE([
run all tests under valgrind : ${use_valgrind}
gcc undefined behaviour sanitizer : ${use_undefined}
gcc address sanitizer : ${use_address}
+ clang memory sanitizer : ${use_msan}
use rpath in tests : ${tests_use_rpath}
test biarch : ${utrace_cv_cc_biarch}
])
@@ -102,7 +102,8 @@ endif
$(LIBDEBUGINFOD_SONAME): $(srcdir)/libdebuginfod.map $(libdebuginfod_so_LIBS)
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
-Wl,--soname,$(LIBDEBUGINFOD_SONAME) \
- -Wl,--version-script,$<,--no-undefined \
+ -Wl,--version-script,$< \
+ $(NO_UNDEFINED) \
-Wl,--whole-archive $(libdebuginfod_so_LIBS) -Wl,--no-whole-archive \
$(libdebuginfod_so_LDLIBS)
@$(textrel_check)
@@ -64,7 +64,8 @@ libasm_so_LIBS = libasm_pic.a
libasm.so: $(srcdir)/libasm.map $(libasm_so_LIBS) $(libasm_so_DEPS)
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
-Wl,--soname,$@.$(VERSION) \
- -Wl,--version-script,$<,--no-undefined \
+ -Wl,--version-script,$< \
+ $(NO_UNDEFINED) \
-Wl,--whole-archive $(libasm_so_LIBS) -Wl,--no-whole-archive \
$(libasm_so_LDLIBS)
@$(textrel_check)
@@ -114,7 +114,8 @@ libdw_so_LDLIBS = $(libdw_so_DEPS) -ldl -lz $(argp_LDADD) $(fts_LIBS) $(obstack_
libdw.so: $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS)
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
-Wl,--soname,$@.$(VERSION),--enable-new-dtags \
- -Wl,--version-script,$<,--no-undefined \
+ -Wl,--version-script,$< \
+ $(NO_UNDEFINED) \
-Wl,--whole-archive $(libdw_so_LIBS) -Wl,--no-whole-archive \
$(libdw_so_LDLIBS)
@$(textrel_check)
@@ -115,7 +115,8 @@ libelf_so_LIBS = libelf_pic.a
libelf.so: $(srcdir)/libelf.map $(libelf_so_LIBS) $(libelf_so_DEPS)
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
-Wl,--soname,$@.$(VERSION) \
- -Wl,--version-script,$<,--no-undefined \
+ -Wl,--version-script,$< \
+ $(NO_UNDEFINED) \
-Wl,--whole-archive $(libelf_so_LIBS) -Wl,--no-whole-archive \
$(libelf_so_LDLIBS)
@$(textrel_check)
@@ -88,12 +88,16 @@ endif
# test_nlist checks its own symbol table, and expects various symbols
# to be in the order as specified in the source file. Explicitly set
-# minimal CFLAGS. But add address sanitizer if in use.
+# minimal CFLAGS. But add sanitizers if in use.
if USE_ADDRESS_SANITIZER
EXTRA_NLIST_CFLAGS=-fsanitize=address
else
+if USE_MEMORY_SANITIZER
+EXTRA_NLIST_CFLAGS=-fsanitize=memory -fsanitize-memory-track-origins
+else
EXTRA_NLIST_CFLAGS=
endif
+endif
test-nlist$(EXEEXT): test-nlist.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
@@ -225,6 +229,10 @@ if USE_ZSTD_COMPRESS
export ELFUTILS_ZSTD = 1
endif
+if USE_MEMORY_SANITIZER
+export ELFUTILS_MEMORY_SANITIZER = 1
+endif
+
if DEBUGINFOD
check_PROGRAMS += debuginfod_build_id_find
# With the dummy delegation doesn't work
@@ -17,5 +17,10 @@
. $srcdir/test-subr.sh
+if test -n "$ELFUTILS_MEMORY_SANITIZER"; then
+ echo "binaries statically linked memory sanitizer are too big"
+ exit 77
+fi
+
# Just makes sure readelf doesn't crash
testrun_on_self_quiet ${abs_top_builddir}/src/readelf -a -w
@@ -17,6 +17,11 @@
. $srcdir/test-subr.sh
+if test -n "$ELFUTILS_MEMORY_SANITIZER"; then
+ echo "binaries statically linked memory sanitizer are too big"
+ exit 77
+fi
+
testfiles hello_i386.ko hello_x86_64.ko hello_ppc64.ko hello_s390.ko \
hello_aarch64.ko hello_m68k.ko hello_riscv64.ko hello_csky.ko \
hello_arc_hs4.ko
@@ -17,6 +17,11 @@
. $srcdir/test-subr.sh
+if test -n "$ELFUTILS_MEMORY_SANITIZER"; then
+ echo "binaries statically linked memory sanitizer are too big"
+ exit 77
+fi
+
# Make sure varlocs doesn't crash, doesn't trigger self-check/asserts
# or leaks running under valgrind.
testrun_on_self_exe ${abs_top_builddir}/tests/varlocs -e