From: Simon Marchi Date: Fri, 14 May 2021 14:23:19 +0000 (-0400) Subject: Add --enable-asan configure option X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=0b0893d4a069f17d1326ebc3bfc9f9f987f411f3 Add --enable-asan configure option It's possible to build babeltrace with AddressSanitizer by adding -fsanitize=address to CFLAGS/LDFLAGS, but it causes some issues. These issues are related to the fact that if libasan.so is to be loaded, it must be the first library to be loaded. When a Python interpreter loads the bt2 module, that pulls in libbabeltrace2.so, which pulls libasan.so. libasan.so then complains about not being the first loaded libraries. The only way I know to fix this is to LD_PRELOAD libasan.so in the Python interpreter. The first case where this happens is when building the Python bindings. This is because the Sphinx tool (so, the Python interpreter) loads the bt2 Python module in order to obtain the documentation. The other case is when running the Python bindings tests, the test runner is in Python, and the .py tests imports the bt2 module. In both cases, libasan unfortunately finds some leaks in the Python interpreter. We must therefore disable leak reporting with ASAN_OPTIONS=detect_leaks=0. This is particularly unfortunate for the Python bindings tests, because it would be nice to know about leaks that are libbabeltrace2's or the tests' fault. But I don't see any way around it. For running Sphinx, we don't care about leaks. Since we need to set some special environment variables when building and checking if AddressSanitizer is used, it's much easier if the build system knows that we want to use AddressSanitizer. This patch therefore adds a new `--enable-asan` option that developers should use in order to use AddressSanitizer, instead of manually adding -fsanitize=address in CFLAGS/LDFLAGS. If `--enable-asan` is used, the following command will be invoked : $(CC) -print-file-name=libasan.so ... to find the path of the libasan.so library associated to the compiler being used (it's important that we pre-load the right version of libasan.so). For the Python bindings documentation generation, the command is used in the Makefile where Sphinx is invoked. For tests, a boolean is written in a generated tests/utils/env.sh file, which is sourced by tests/utils/utils.sh and the command is then used when running the tests. Change-Id: I5e0ca10532605cfdfda08b3ee4fcc39922480797 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/5860 Tested-by: jenkins Reviewed-by: Michael Jeanson --- diff --git a/configure.ac b/configure.ac index 673fd720..85f422a1 100644 --- a/configure.ac +++ b/configure.ac @@ -409,6 +409,9 @@ AE_FEATURE([man-pages],[Do not build and install man pages (already built in a d AE_FEATURE_DEFAULT_DISABLE AE_FEATURE([Werror],[Treat compiler warnings as errors.]) +# When given, build with AddressSanitizer. +AE_FEATURE_DEFAULT_DISABLE +AE_FEATURE([asan],[Build with AddressSanitizer.]) ## ## ## Check for conflicting features selection ## @@ -459,6 +462,7 @@ AM_CONDITIONAL([ENABLE_BUILT_IN_PLUGINS], AE_IS_FEATURE_ENABLED([built-in-plugin AM_CONDITIONAL([ENABLE_BUILT_IN_PYTHON_PLUGIN_SUPPORT], AE_IS_FEATURE_ENABLED([built-in-python-plugin-support])) AM_CONDITIONAL([ENABLE_MAN_PAGES], AE_IS_FEATURE_ENABLED([man-pages])) AM_CONDITIONAL([ENABLE_PYTHON_COMMON_DEPS], AE_IS_FEATURE_ENABLED([python-bindings]) || AE_IS_FEATURE_ENABLED([python-plugins])) +AM_CONDITIONAL([ENABLE_ASAN], AE_IS_FEATURE_ENABLED([asan])) ## ## @@ -476,6 +480,8 @@ AE_IF_FEATURE_ENABLED([built-in-python-plugin-support], AE_IF_FEATURE_ENABLED([debug-info], [ENABLE_DEBUG_INFO_VAL=1], [ENABLE_DEBUG_INFO_VAL=0]) AC_SUBST([ENABLE_DEBUG_INFO_VAL]) +AE_IF_FEATURE_ENABLED([asan], [ENABLE_ASAN=1], [ENABLE_ASAN=0]) +AC_SUBST([ENABLE_ASAN]) ## ## ## Check for optionnal features dependencies ## @@ -634,13 +640,21 @@ AS_IF([test "x$exec_prefix" = xNONE], [ AC_SUBST(LIBDIR) +# If --enable-asan is used... +AE_IF_FEATURE_ENABLED([asan], [ + # ... add -fsanitize=address to the *FLAGS variables. + ASAN_CFLAGS="-fsanitize=address" + ASAN_CXXFLAGS="-fsanitize=address" + ASAN_LDFLAGS="-fsanitize=address" +]) # CFLAGS from libraries (the glib ones are needed for the following sizeof # test). -AM_CFLAGS="${PTHREAD_CFLAGS} ${GLIB_CFLAGS}" -AM_CXXFLAGS="${PTHREAD_CFLAGS} ${GLIB_CFLAGS}" +AM_CFLAGS="${PTHREAD_CFLAGS} ${GLIB_CFLAGS} ${ASAN_CFLAGS}" +AM_CXXFLAGS="${PTHREAD_CFLAGS} ${GLIB_CFLAGS} ${ASAN_CXXFLAGS}" +AM_LDFLAGS="${ASAN_LDFLAGS}" # Check that the current size_t matches the size that glib thinks it should # be. This catches problems on multi-arch where people try to do a 32-bit @@ -742,9 +756,10 @@ WARN_CFLAGS="${WARN_CFLAGS} -Wold-style-definition -Wstrict-prototypes" AM_CXXFLAGS="${AM_CXXFLAGS} ${WARN_CXXFLAGS}" AM_CFLAGS="${AM_CFLAGS} ${WARN_CFLAGS}" -# Done for AM_CXXFLAGS and AM_CFLAGS. +# Done for AM_CXXFLAGS, AM_CFLAGS and AM_LDFLAGS. AC_SUBST(AM_CXXFLAGS) AC_SUBST(AM_CFLAGS) +AC_SUBST(AM_LDFLAGS) # Set global CPPFLAGS in AM_CPPFLAGS AM_CPPFLAGS="-I\$(top_srcdir)/include -I\$(top_builddir)/src -I\$(top_srcdir)/src -include common/config.h" diff --git a/doc/bindings/python/Makefile.am b/doc/bindings/python/Makefile.am index f5d8490a..a5521967 100644 --- a/doc/bindings/python/Makefile.am +++ b/doc/bindings/python/Makefile.am @@ -14,12 +14,30 @@ PYTHON_BT2_BUILD_LIB_DIR = $(abs_top_builddir)/src/bindings/python/bt2/build/bui PP = $(PYTHON_BT2_BUILD_LIB_DIR) LLP = $(abs_top_builddir)/src/lib/.libs +# Sphinx loads the bt2 Python module and thus libbabeltrace2.so. If +# AddressSanitizer is used, we must preload libasan.so so that libasan doesn't +# complain about not being the first loaded library. +# +# Python produces some leaks, so disable leak detection (we don't care about +# leaks here anyway). +if ENABLE_ASAN +MAYBE_LD_PRELOAD = LD_PRELOAD="$$($(CC) -print-file-name=libasan.so):$(LD_PRELOAD)" +MAYBE_ASAN_OPTIONS = ASAN_OPTIONS="$(ASAN_OPTIONS),detect_leaks=0" +endif + # `PATH` is used as a replacement for `LD_LIBRARY_PATH` on Windows # builds (Cygwin, MinGW). # # `DYLD_LIBRARY_PATH` is used a replacement for `LD_LIBRARY_PATH` on # macOS builds. -SPHINXBUILD = PATH="$(LLP):$$PATH" PYTHONPATH="$(PP):$(SPHINX_EXT_DIR)" LD_LIBRARY_PATH="$(LLP)" DYLD_LIBRARY_PATH="$(LLP)" $(PYTHON) -m sphinx +SPHINXBUILD = \ + PATH="$(LLP):$$PATH" \ + PYTHONPATH="$(PP):$(SPHINX_EXT_DIR)" \ + LD_LIBRARY_PATH="$(LLP)" \ + DYLD_LIBRARY_PATH="$(LLP)" \ + $(MAYBE_LD_PRELOAD) \ + $(MAYBE_ASAN_OPTIONS) \ + $(PYTHON) -m sphinx SPHINX_SRC = \ $(SPHINX_SOURCE_DIR)/common.rst \ $(SPHINX_SOURCE_DIR)/index.rst \ diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index ec30c005..c8e3eb44 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -3,7 +3,7 @@ # Since the shared object used by the python bindings is not built with # libtool, we need to add the directory containing libbabeltrace2 to the # linker path. -AM_LDFLAGS=-L$(top_builddir)/src/lib/.libs +AM_LDFLAGS += -L$(top_builddir)/src/lib/.libs INSTALLED_FILES=$(builddir)/installed_files.txt diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index bfe868a1..2428b489 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -44,7 +44,7 @@ babeltrace2_bin_SOURCES = \ # -Wl,--no-as-needed is needed for recent gold linker who seems to think # it knows better and considers libraries with constructors having # side-effects as dead code. -babeltrace2_bin_LDFLAGS = $(LD_NO_AS_NEEDED) +babeltrace2_bin_LDFLAGS = $(AM_LDFLAGS) $(LD_NO_AS_NEEDED) # Add all the convenience libraries used by Babeltrace plugins and the # library. They will be used when embedding plugins (--enable-built-in-plugins), diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am index 8a3908d0..c857372a 100644 --- a/src/compat/Makefile.am +++ b/src/compat/Makefile.am @@ -7,6 +7,7 @@ libcompat_la_SOURCES = \ mman.h libcompat_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LD_NO_AS_NEEDED) noinst_HEADERS = \ diff --git a/src/ctf-writer/Makefile.am b/src/ctf-writer/Makefile.am index 6e05b8d5..2e979b01 100644 --- a/src/ctf-writer/Makefile.am +++ b/src/ctf-writer/Makefile.am @@ -49,8 +49,10 @@ libbabeltrace2_ctf_writer_la_SOURCES = \ writer.c \ writer.h -libbabeltrace2_ctf_writer_la_LDFLAGS = $(LT_NO_UNDEFINED) \ - -version-info $(BABELTRACE_LIBRARY_VERSION) +libbabeltrace2_ctf_writer_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(LT_NO_UNDEFINED) \ + -version-info $(BABELTRACE_LIBRARY_VERSION) libbabeltrace2_ctf_writer_la_LIBADD = \ $(top_builddir)/src/logging/libbabeltrace2-logging.la \ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index c6367626..a9113810 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -26,8 +26,10 @@ libbabeltrace2_la_SOURCES = \ value.c \ value.h -libbabeltrace2_la_LDFLAGS = $(LT_NO_UNDEFINED) \ - -version-info $(BABELTRACE_LIBRARY_VERSION) +libbabeltrace2_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(LT_NO_UNDEFINED) \ + -version-info $(BABELTRACE_LIBRARY_VERSION) libbabeltrace2_la_LIBADD = \ prio-heap/libprio-heap.la \ diff --git a/src/plugins/ctf/Makefile.am b/src/plugins/ctf/Makefile.am index 104229d2..24a43401 100644 --- a/src/plugins/ctf/Makefile.am +++ b/src/plugins/ctf/Makefile.am @@ -12,6 +12,7 @@ plugin_LTLIBRARIES = babeltrace-plugin-ctf.la babeltrace_plugin_ctf_la_SOURCES = plugin.c babeltrace_plugin_ctf_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -avoid-version -module $(LD_NOTEXT) diff --git a/src/plugins/lttng-utils/Makefile.am b/src/plugins/lttng-utils/Makefile.am index d01e36fa..0beeadf2 100644 --- a/src/plugins/lttng-utils/Makefile.am +++ b/src/plugins/lttng-utils/Makefile.am @@ -17,6 +17,7 @@ babeltrace_plugin_lttng_utils_la_SOURCES = \ plugin.c babeltrace_plugin_lttng_utils_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -avoid-version -module $(LD_NOTEXT) \ $(ELFUTILS_LIBS) diff --git a/src/plugins/text/Makefile.am b/src/plugins/text/Makefile.am index 9d8ed88d..9e69ad80 100644 --- a/src/plugins/text/Makefile.am +++ b/src/plugins/text/Makefile.am @@ -7,6 +7,7 @@ plugin_LTLIBRARIES = babeltrace-plugin-text.la babeltrace_plugin_text_la_SOURCES = plugin.c babeltrace_plugin_text_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -avoid-version -module $(LD_NOTEXT) diff --git a/src/plugins/utils/Makefile.am b/src/plugins/utils/Makefile.am index 5cacc961..71881317 100644 --- a/src/plugins/utils/Makefile.am +++ b/src/plugins/utils/Makefile.am @@ -7,6 +7,7 @@ plugin_LTLIBRARIES = babeltrace-plugin-utils.la babeltrace_plugin_utils_la_SOURCES = plugin.c babeltrace_plugin_utils_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -avoid-version -module $(LD_NOTEXT) babeltrace_plugin_utils_la_LIBADD = \ diff --git a/src/python-plugin-provider/Makefile.am b/src/python-plugin-provider/Makefile.am index 822e5534..3d3a11fe 100644 --- a/src/python-plugin-provider/Makefile.am +++ b/src/python-plugin-provider/Makefile.am @@ -11,6 +11,7 @@ babeltrace2_python_plugin_provider_la_SOURCES = \ python-plugin-provider.h babeltrace2_python_plugin_provider_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -avoid-version -module \ $(PYTHON_LDFLAGS) diff --git a/tests/lib/test-plugin-plugins/Makefile.am b/tests/lib/test-plugin-plugins/Makefile.am index 62e48f7e..4725a564 100644 --- a/tests/lib/test-plugin-plugins/Makefile.am +++ b/tests/lib/test-plugin-plugins/Makefile.am @@ -5,6 +5,7 @@ noinst_LTLIBRARIES = plugin-minimal.la plugin-sfs.la # the minimal plugin plugin_minimal_la_SOURCES = minimal.c plugin_minimal_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -rpath / -avoid-version -module $(LD_NOTEXT) plugin_minimal_la_LIBADD = \ @@ -15,6 +16,7 @@ plugin_minimal_la_LIBADD = \ # source/filter/sink plugin plugin_sfs_la_SOURCES = sfs.c plugin_sfs_la_LDFLAGS = \ + $(AM_LDFLAGS) \ $(LT_NO_UNDEFINED) \ -rpath / -avoid-version -module $(LD_NOTEXT) plugin_sfs_la_LIBADD = \ diff --git a/tests/utils/env.sh.in b/tests/utils/env.sh.in index af34046b..96f4fc09 100644 --- a/tests/utils/env.sh.in +++ b/tests/utils/env.sh.in @@ -40,3 +40,16 @@ if [ "x${BT_TESTS_SED_BIN:-}" = "x" ]; then BT_TESTS_SED_BIN="@SED@" fi export BT_TESTS_SED_BIN + +if [ "x${BT_TESTS_CC_BIN:-}" = "x" ]; then + BT_TESTS_CC_BIN="@CC@" +fi +export BT_TESTS_CC_BIN + + +### Optional features ### + +if [ "x${BT_TESTS_ENABLE_ASAN:-}" = "x" ]; then + BT_TESTS_ENABLE_ASAN="@ENABLE_ASAN@" +fi +export BT_TESTS_ENABLE_ASAN diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index 9d9b639b..3cbea160 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -121,6 +121,19 @@ if [ "x${BT_TESTS_SED_BIN:-}" = "x" ]; then fi export BT_TESTS_SED_BIN +if [ "x${BT_TESTS_CC_BIN:-}" = "x" ]; then + BT_TESTS_CC_BIN="cc" +fi +export BT_TESTS_CC_BIN + + +### Optional features ### + +if [ "x${BT_TESTS_ENABLE_ASAN:-}" = "x" ]; then + BT_TESTS_ENABLE_ASAN="0" +fi +export BT_TESTS_ENABLE_ASAN + # Data files path BT_TESTS_DATADIR="${BT_TESTS_SRCDIR}/data" @@ -293,6 +306,7 @@ check_coverage() { # bt2 Python bindings. run_python_bt2() { local env_args + local lib_asan env_args=( "BABELTRACE_PYTHON_BT2_NO_TRACEBACK=1" \ @@ -322,6 +336,20 @@ run_python_bt2() { env_args+=("PYTHONHOME=$($BT_TESTS_PYTHON_CONFIG_BIN --prefix)") fi + # If AddressSanitizer is used, we must preload libasan.so so that + # libasan doesn't complain about not being the first loaded library. + # + # Python and sed (executed as part of the libtool wrapper) produce some + # leaks, so we must unfortunately disable leak detection. Append it to + # existing ASAN_OPTIONS, such that we override the user's value if it + # contains detect_leaks=1. + if [ "x${BT_TESTS_ENABLE_ASAN:-}" = "x1" ]; then + lib_asan=$(${BT_TESTS_CC_BIN} -print-file-name=libasan.so) + + env_args+=("LD_PRELOAD=${lib_asan}:${LD_PRELOAD:-}") + env_args+=("ASAN_OPTIONS=${ASAN_OPTIONS:-},detect_leaks=0") + fi + env "${env_args[@]}" "$@" }