From 2b2f9046d4e1f915cdcea9cd80b7fb304a36f030 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 5 Feb 2016 15:31:14 +0000 Subject: [PATCH 1/6] Problem: no Makefile target for Valgrind Solution: import ax_valgrind_check.m4 macro file to provide a conveniente automake hook to run Valgrind on all tests. Add --enable-valgrind to ./configure call and then run make check-valgrind to run memcheck, helgrind, drd and sgcheck on all tests. Run check-valgrind-memcheck to run only memcheck. --- Makefile.am | 2 + configure.ac | 2 + m4/ax_valgrind_check.m4 | 233 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 m4/ax_valgrind_check.m4 diff --git a/Makefile.am b/Makefile.am index 34fe8cc4..5bdba509 100644 --- a/Makefile.am +++ b/Makefile.am @@ -777,3 +777,5 @@ dist-hook: maintainer-clean-local: -rm -rf $(top_srcdir)/config + +@VALGRIND_CHECK_RULES@ diff --git a/configure.ac b/configure.ac index d171ea82..de83ba82 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,7 @@ m4_pattern_allow([AC_PROG_CC_C99]) m4_include([m4/ax_check_compile_flag.m4]) m4_include([m4/ax_cxx_compile_stdcxx_11.m4]) m4_include([m4/ax_code_coverage.m4]) +m4_include([m4/ax_valgrind_check.m4]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) # This lets us use PACKAGE_VERSION in Makefiles @@ -66,6 +67,7 @@ AC_PATH_PROG([ASCIIDOC], [asciidoc]) LIBZMQ_CONFIG_LIBTOOL AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL +AX_VALGRIND_CHECK # Check whether to build a with debug symbols LIBZMQ_CHECK_ENABLE_DEBUG diff --git a/m4/ax_valgrind_check.m4 b/m4/ax_valgrind_check.m4 new file mode 100644 index 00000000..2dd8f718 --- /dev/null +++ b/m4/ax_valgrind_check.m4 @@ -0,0 +1,233 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_VALGRIND_CHECK() +# +# DESCRIPTION +# +# Checks whether Valgrind is present and, if so, allows running `make +# check` under a variety of Valgrind tools to check for memory and +# threading errors. +# +# Defines VALGRIND_CHECK_RULES which should be substituted in your +# Makefile; and $enable_valgrind which can be used in subsequent configure +# output. VALGRIND_ENABLED is defined and substituted, and corresponds to +# the value of the --enable-valgrind option, which defaults to being +# enabled if Valgrind is installed and disabled otherwise. +# +# If unit tests are written using a shell script and automake's +# LOG_COMPILER system, the $(VALGRIND) variable can be used within the +# shell scripts to enable Valgrind, as described here: +# +# https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html +# +# Usage example: +# +# configure.ac: +# +# AX_VALGRIND_CHECK +# +# Makefile.am: +# +# @VALGRIND_CHECK_RULES@ +# VALGRIND_SUPPRESSIONS_FILES = my-project.supp +# EXTRA_DIST = my-project.supp +# +# This results in a "check-valgrind" rule being added to any Makefile.am +# which includes "@VALGRIND_CHECK_RULES@" (assuming the module has been +# configured with --enable-valgrind). Running `make check-valgrind` in +# that directory will run the module's test suite (`make check`) once for +# each of the available Valgrind tools (out of memcheck, helgrind, drd and +# sgcheck), and will output results to test-suite-$toolname.log for each. +# The target will succeed if there are zero errors and fail otherwise. +# +# Alternatively, a "check-valgrind-$TOOL" rule will be added, for $TOOL in +# memcheck, helgrind, drd and sgcheck. These are useful because often only +# some of those tools can be ran cleanly on a codebase. +# +# The macro supports running with and without libtool. +# +# LICENSE +# +# Copyright (c) 2014, 2015, 2016 Philip Withnall +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 9 + +AC_DEFUN([AX_VALGRIND_CHECK],[ + dnl Check for --enable-valgrind + AC_ARG_ENABLE([valgrind], + [AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])], + [enable_valgrind=$enableval],[enable_valgrind=]) + + AS_IF([test "$enable_valgrind" != "no"],[ + # Check for Valgrind. + AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind]) + AS_IF([test "$VALGRIND" = ""],[ + AS_IF([test "$enable_valgrind" = "yes"],[ + AC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind]) + ],[ + enable_valgrind=no + ]) + ],[ + enable_valgrind=yes + ]) + ]) + + AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"]) + AC_SUBST([VALGRIND_ENABLED],[$enable_valgrind]) + + # Check for Valgrind tools we care about. + m4_define([valgrind_tool_list],[[memcheck], [helgrind], [drd], [exp-sgcheck]]) + + AS_IF([test "$VALGRIND" != ""],[ + m4_foreach([vgtool],[valgrind_tool_list],[ + m4_define([vgtooln],AS_TR_SH(vgtool)) + m4_define([ax_cv_var],[ax_cv_valgrind_tool_]vgtooln) + AC_CACHE_CHECK([for Valgrind tool ]vgtool,ax_cv_var,[ + ax_cv_var= + AS_IF([`$VALGRIND --tool=vgtool --help >/dev/null 2>&1`],[ + ax_cv_var="vgtool" + ]) + ]) + + AC_SUBST([VALGRIND_HAVE_TOOL_]vgtooln,[$ax_cv_var]) + ]) + ]) + +[VALGRIND_CHECK_RULES=' +# Valgrind check +# +# Optional: +# - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions +# files to load. (Default: empty) +# - VALGRIND_FLAGS: General flags to pass to all Valgrind tools. +# (Default: --num-callers=30) +# - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of: +# memcheck, helgrind, drd, sgcheck). (Default: various) + +# Optional variables +VALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES)) +VALGRIND_FLAGS ?= --num-callers=30 +VALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no +VALGRIND_helgrind_FLAGS ?= --history-level=approx +VALGRIND_drd_FLAGS ?= +VALGRIND_sgcheck_FLAGS ?= + +# Internal use +valgrind_tools = memcheck helgrind drd sgcheck +valgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools))) + +valgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS) +valgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS) +valgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS) +valgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS) + +valgrind_quiet = $(valgrind_quiet_$(V)) +valgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY)) +valgrind_quiet_0 = --quiet + +# Support running with and without libtool. +ifneq ($(LIBTOOL),) +valgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute +else +valgrind_lt = +endif + +# Use recursive makes in order to ignore errors during check +check-valgrind: +ifeq ($(VALGRIND_ENABLED),yes) + -$(foreach tool,$(valgrind_tools), \ + $(if $(VALGRIND_HAVE_TOOL_$(tool))$(VALGRIND_HAVE_TOOL_exp_$(tool)), \ + $(MAKE) $(AM_MAKEFLAGS) -k check-valgrind-tool VALGRIND_TOOL=$(tool); \ + ) \ + ) +else + @echo "Need to reconfigure with --enable-valgrind" +endif + +# Valgrind running +VALGRIND_TESTS_ENVIRONMENT = \ + $(TESTS_ENVIRONMENT) \ + env VALGRIND=$(VALGRIND) \ + G_SLICE=always-malloc,debug-blocks \ + G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly + +VALGRIND_LOG_COMPILER = \ + $(valgrind_lt) \ + $(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS) + +check-valgrind-tool: +ifeq ($(VALGRIND_ENABLED),yes) + $(MAKE) check-TESTS \ + TESTS_ENVIRONMENT="$(VALGRIND_TESTS_ENVIRONMENT)" \ + LOG_COMPILER="$(VALGRIND_LOG_COMPILER)" \ + LOG_FLAGS="$(valgrind_$(VALGRIND_TOOL)_flags)" \ + TEST_SUITE_LOG=test-suite-$(VALGRIND_TOOL).log +else + @echo "Need to reconfigure with --enable-valgrind" +endif + +check-valgrind-memcheck: +ifeq ($(VALGRIND_ENABLED),yes) + $(MAKE) check-TESTS \ + TESTS_ENVIRONMENT="$(VALGRIND_TESTS_ENVIRONMENT)" \ + LOG_COMPILER="$(VALGRIND_LOG_COMPILER)" \ + LOG_FLAGS="$(valgrind_memcheck_flags)" \ + TEST_SUITE_LOG=test-suite-memcheck.log +else + @echo "Need to reconfigure with --enable-valgrind" +endif + +check-valgrind-helgrind: +ifeq ($(VALGRIND_ENABLED),yes) + $(MAKE) check-TESTS \ + TESTS_ENVIRONMENT="$(VALGRIND_TESTS_ENVIRONMENT)" \ + LOG_COMPILER="$(VALGRIND_LOG_COMPILER)" \ + LOG_FLAGS="$(valgrind_helgrind_flags)" \ + TEST_SUITE_LOG=test-suite-helgrind.log +else + @echo "Need to reconfigure with --enable-valgrind" +endif + +check-valgrind-drd: +ifeq ($(VALGRIND_ENABLED),yes) + $(MAKE) check-TESTS \ + TESTS_ENVIRONMENT="$(VALGRIND_TESTS_ENVIRONMENT)" \ + LOG_COMPILER="$(VALGRIND_LOG_COMPILER)" \ + LOG_FLAGS="$(valgrind_drd_flags)" \ + TEST_SUITE_LOG=test-suite-drd.log +else + @echo "Need to reconfigure with --enable-valgrind" +endif + +check-valgrind-sgcheck: +ifeq ($(VALGRIND_ENABLED),yes) + $(MAKE) check-TESTS \ + TESTS_ENVIRONMENT="$(VALGRIND_TESTS_ENVIRONMENT)" \ + LOG_COMPILER="$(VALGRIND_LOG_COMPILER)" \ + LOG_FLAGS="$(valgrind_sgcheck_flags)" \ + TEST_SUITE_LOG=test-suite-sgcheck.log +else + @echo "Need to reconfigure with --enable-valgrind" +endif + +A''M_DISTCHECK_CONFIGURE_FLAGS ?= +A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind + +MOSTLYCLEANFILES ?= +MOSTLYCLEANFILES += $(valgrind_log_files) + +.PHONY: check-valgrind check-valgrind-tool +'] + + AC_SUBST([VALGRIND_CHECK_RULES]) + m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])]) +]) From ebc73160694fdc4d024f5b5d156efa489208e3d6 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 5 Feb 2016 21:05:11 +0000 Subject: [PATCH 2/6] Problem: CI doesn't run Valgrind Solution: run Valgrind only on the default Linux build to avoid increasing the runtime. --- .travis.yml | 4 ++++ builds/valgrind/ci_build.sh | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100755 builds/valgrind/ci_build.sh diff --git a/.travis.yml b/.travis.yml index 9a470656..9fb78235 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,11 +13,14 @@ env: - BUILD_TYPE=default CURVE=libsodium - BUILD_TYPE=default - BUILD_TYPE=coverage CURVE=tweetnacl +- BUILD_TYPE=valgrind CURVE=tweetnacl matrix: exclude: - env: BUILD_TYPE=coverage CURVE=tweetnacl os: osx + - env: BUILD_TYPE=valgrind CURVE=tweetnacl + os: osx sudo: false @@ -28,6 +31,7 @@ addons: packages: - cmake - lcov + - valgrind before_install: - if [ $TRAVIS_OS_NAME == "osx" ] ; then brew update; brew install binutils ; fi diff --git a/builds/valgrind/ci_build.sh b/builds/valgrind/ci_build.sh new file mode 100755 index 00000000..26149592 --- /dev/null +++ b/builds/valgrind/ci_build.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -x + +mkdir tmp +BUILD_PREFIX=$PWD/tmp + +CONFIG_OPTS=() +CONFIG_OPTS+=("CFLAGS=-I${BUILD_PREFIX}/include") +CONFIG_OPTS+=("CPPFLAGS=-I${BUILD_PREFIX}/include") +CONFIG_OPTS+=("CXXFLAGS=-I${BUILD_PREFIX}/include") +CONFIG_OPTS+=("LDFLAGS=-L${BUILD_PREFIX}/lib") +CONFIG_OPTS+=("PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig") +CONFIG_OPTS+=("--prefix=${BUILD_PREFIX}") +CONFIG_OPTS+=("--enable-valgrind") + +if [ -z $CURVE ]; then + CONFIG_OPTS+=("--disable-curve") +elif [ $CURVE == "libsodium" ]; then + CONFIG_OPTS+=("--with-libsodium=yes") + + git clone --depth 1 -b stable git://github.com/jedisct1/libsodium.git + ( cd libsodium; ./autogen.sh; ./configure --prefix=$BUILD_PREFIX; make install) +fi + +# Build, check, and install from local source +( cd ../..; ./autogen.sh && ./configure "${CONFIG_OPTS[@]}" && make -j5 && make VERBOSE=1 check-valgrind-memcheck) || exit 1 From 00e0957640466152b016be3ac570c056eb9192d4 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Fri, 18 Mar 2016 20:55:39 +0000 Subject: [PATCH 3/6] Problem: false positive on valgrind 3.10 Solution: update builds/valgrind/valgrind.supp to ignore glibc's __libc_freeres calls. This code runs after the program exits, and tries to de-allocate memory allocated internally by glibc, so it has nothing to do with libzmq code. This suppression is added by default in newer versions of Valgrind, not yet available on older distributions. --- Makefile.am | 2 ++ builds/valgrind/valgrind.supp | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/Makefile.am b/Makefile.am index 5bdba509..d301c990 100644 --- a/Makefile.am +++ b/Makefile.am @@ -779,3 +779,5 @@ maintainer-clean-local: -rm -rf $(top_srcdir)/config @VALGRIND_CHECK_RULES@ + +VALGRIND_SUPPRESSIONS_FILES = builds/valgrind/valgrind.supp diff --git a/builds/valgrind/valgrind.supp b/builds/valgrind/valgrind.supp index ccd71a61..b8a6bc77 100644 --- a/builds/valgrind/valgrind.supp +++ b/builds/valgrind/valgrind.supp @@ -12,3 +12,11 @@ fun:send ... } +{ + + Memcheck:Free + fun:free + ... + fun:__libc_freeres + ... +} From 9d94eb11b38dbd7e3c74de2ed01c22a17229e166 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 19 Mar 2016 16:28:35 +0000 Subject: [PATCH 4/6] Problem: test_fork causes valgrind false positive Solution: do not run test_fork if --enable-valgrind is set. Note that later versions of Valgrind (3.11) not yet available in all distributions fix this problem, so we might revert in the future. --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index d301c990..c61a43d9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -657,6 +657,7 @@ tests_test_use_fd_tcp_SOURCES = \ tests_test_use_fd_tcp_LDADD = src/libzmq.la if HAVE_FORK +if !VALGRIND_ENABLED test_apps += tests/test_fork tests_test_fork_SOURCES = tests/test_fork.cpp @@ -665,6 +666,7 @@ tests_test_fork_LDADD = src/libzmq.la endif endif endif +endif if BUILD_TIPC test_apps += \ From 0eca822b8fc0c8ef3b452d1a07a8c7ae32a3596c Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 19 Mar 2016 16:30:59 +0000 Subject: [PATCH 5/6] Problem: Valgrind in Ubuntu Precise is too old Solution: run Travis CI in newer Trusty (14.04 LTS) release. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9fb78235..c5a0f3da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ os: - linux - osx +dist: trusty + env: - BUILD_TYPE=default CURVE=tweetnacl - BUILD_TYPE=android CURVE=tweetnacl @@ -22,12 +24,10 @@ matrix: - env: BUILD_TYPE=valgrind CURVE=tweetnacl os: osx -sudo: false +sudo: required addons: apt: - sources: - - kubuntu-backports packages: - cmake - lcov @@ -40,7 +40,7 @@ before_script: # ZMQ stress tests need more open socket (files) than the usual default # On OSX, it seems the way to set the max files limit is constantly changing, so # try to use all known knobs to ensure compatibility across various versions -- if [ $TRAVIS_OS_NAME == "osx" ] ; then sudo sysctl -w kern.maxfiles=64000 ; sudo sysctl -w kern.maxfilesperproc=64000 ; sudo launchctl limit maxfiles 64000 64000 ; fi ; ulimit -n 64000 +- if [ $TRAVIS_OS_NAME == "osx" ] ; then sudo sysctl -w kern.maxfiles=64000 ; sudo sysctl -w kern.maxfilesperproc=64000 ; sudo launchctl limit maxfiles 64000 64000 ; ulimit -n 64000; fi # Build and check this project according to the BUILD_TYPE script: ./ci_build.sh From dc27ad41d28217fefecbdc77841d86c5a5a43db8 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 19 Mar 2016 21:35:40 +0000 Subject: [PATCH 6/6] Problem: coveralls uses wrong path on Trusty Solution: pass built-root when calling coveralls, to help it find the right path to the source code. --- builds/coverage/ci_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builds/coverage/ci_build.sh b/builds/coverage/ci_build.sh index 065f2bfb..e9f836b4 100755 --- a/builds/coverage/ci_build.sh +++ b/builds/coverage/ci_build.sh @@ -26,4 +26,4 @@ fi pip install --user cpp-coveralls # Build, check, and install from local source -( cd ../..; ./autogen.sh && ./configure "${CONFIG_OPTS[@]}" && make -j5 && make check && coveralls --exclude tests --gcov-options '\-lp') || exit 1 +( cd ../..; ./autogen.sh && ./configure "${CONFIG_OPTS[@]}" && make -j5 && make check && coveralls --exclude tests --build-root . --gcov-options '\-lp') || exit 1