build+ci: enable AddressSanitizer and LeakSanitizer for unit tests
Refs: #2589, #4206
Change-Id: Ie9770134ff87fce438029b97c9ed61dbef3a71a3
diff --git a/.jenkins.d/20-build.sh b/.jenkins.d/20-build.sh
index 464a7ea..6306a52 100755
--- a/.jenkins.d/20-build.sh
+++ b/.jenkins.d/20-build.sh
@@ -6,8 +6,6 @@
git submodule sync
git submodule update
-COVERAGE=$( python -c "print '--with-coverage' if 'code-coverage' in '$JOB_NAME' else ''" )
-
# Cleanup
sudo ./waf -j1 --color=yes distclean
@@ -25,13 +23,16 @@
# Cleanup
sudo ./waf -j1 --color=yes distclean
+if [[ $JOB_NAME == *"code-coverage" ]]; then
+ COVERAGE="--with-coverage"
+elif [[ -n $BUILD_WITH_ASAN || -z $TRAVIS ]]; then
+ ASAN="--with-sanitizer=address"
+fi
+
# Configure/build in optimized mode with tests
-./waf -j1 --color=yes configure --with-tests $COVERAGE
+./waf -j1 --color=yes configure --with-tests $COVERAGE $ASAN
./waf -j1 --color=yes build
# (tests will be run against optimized version)
-./waf configure --color=yes --with-tests $COVERAGE
-
-./waf -j1 --color=yes
sudo ./waf install --color=yes
diff --git a/.jenkins.d/30-tests.sh b/.jenkins.d/30-tests.sh
index 633dfa7..6be5a4a 100755
--- a/.jenkins.d/30-tests.sh
+++ b/.jenkins.d/30-tests.sh
@@ -4,4 +4,14 @@
rm -Rf ~/.ndn
+ASAN_OPTIONS="color=always"
+ASAN_OPTIONS+=":detect_stack_use_after_return=true"
+ASAN_OPTIONS+=":check_initialization_order=true"
+ASAN_OPTIONS+=":strict_init_order=true"
+ASAN_OPTIONS+=":detect_invalid_pointer_pairs=1"
+ASAN_OPTIONS+=":detect_container_overflow=false"
+ASAN_OPTIONS+=":strict_string_checks=true"
+ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
+export ASAN_OPTIONS
+
./build/unit-tests-nlsr -l test_suite
diff --git a/.waf-tools/default-compiler-flags.py b/.waf-tools/default-compiler-flags.py
index 562d192..7544cec 100644
--- a/.waf-tools/default-compiler-flags.py
+++ b/.waf-tools/default-compiler-flags.py
@@ -60,7 +60,7 @@
supportedFlags += [flag]
self.end_msg(' '.join(supportedFlags))
- self.env.CXXFLAGS = supportedFlags + self.env.CXXFLAGS
+ self.env.prepend_value('CXXFLAGS', supportedFlags)
@Configure.conf
def add_supported_linkflags(self, linkflags):
@@ -78,8 +78,7 @@
supportedFlags += [flag]
self.end_msg(' '.join(supportedFlags))
- self.env.LINKFLAGS = supportedFlags + self.env.LINKFLAGS
-
+ self.env.prepend_value('LINKFLAGS', supportedFlags)
class CompilerFlags(object):
def getGeneralFlags(self, conf):
diff --git a/.waf-tools/sanitizers.py b/.waf-tools/sanitizers.py
new file mode 100644
index 0000000..a8fe55d
--- /dev/null
+++ b/.waf-tools/sanitizers.py
@@ -0,0 +1,22 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def options(opt):
+ opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers',
+ help='Comma-separated list of compiler sanitizers to enable [default=none]')
+
+def configure(conf):
+ for san in conf.options.sanitizers.split(','):
+ if not san:
+ continue
+
+ sanflag = '-fsanitize=%s' % san
+ conf.start_msg('Checking if compiler supports %s' % sanflag)
+
+ if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'],
+ linkflags=[sanflag], mandatory=False):
+ conf.end_msg('yes')
+ conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer'])
+ conf.env.append_unique('LINKFLAGS', [sanflag])
+ else:
+ conf.end_msg('no', color='RED')
+ conf.fatal('%s sanitizer is not supported by the current compiler' % san)
diff --git a/AUTHORS.md b/AUTHORS.md
index bc84cdf..9888bde 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -43,6 +43,9 @@
* Junxiao Shi <https://www.cs.arizona.edu/people/shijunxiao/>
+* University Pierre & Marie Curie, Sorbonne University
+
+ * Davide Pesavento <https://www.linkedin.com/in/davidepesavento>
## Queries about NLSR
diff --git a/tests/test-sync-logic-handler.cpp b/tests/test-sync-logic-handler.cpp
index 6e47e1c..24bd065 100644
--- a/tests/test-sync-logic-handler.cpp
+++ b/tests/test-sync-logic-handler.cpp
@@ -158,13 +158,12 @@
receiveUpdate(updateName, syncSeqNo, sync_hrdry);
- std::vector<ndn::Interest>& interests = face->sentInterests;
-
- std::vector<ndn::Interest>::iterator it = interests.begin();
-
// In HR dry-state all LSA's should be published
- BOOST_REQUIRE_EQUAL(interests.size(), 1);
- BOOST_CHECK_EQUAL(it->getName().getPrefix(-1), updateName + "/");
+ const auto& it = std::find_if(face->sentInterests.begin(), face->sentInterests.end(),
+ [updateName] (const ndn::Interest& interest) {
+ return interest.getName().getPrefix(-1) == updateName + "/";
+ });
+ BOOST_REQUIRE(it != face->sentInterests.end());
}
}
diff --git a/wscript b/wscript
index 961c327..1f25960 100644
--- a/wscript
+++ b/wscript
@@ -1,7 +1,7 @@
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
"""
-Copyright (c) 2014-2016, The University of Memphis,
+Copyright (c) 2014-2017, The University of Memphis,
Regents of the University of California,
Arizona Board of Regents.
@@ -32,7 +32,7 @@
def options(opt):
opt.load(['compiler_cxx', 'gnu_dirs'])
- opt.load(['default-compiler-flags', 'coverage',
+ opt.load(['default-compiler-flags', 'coverage', 'sanitizers',
'boost', 'doxygen', 'sphinx_build'],
tooldir=['.waf-tools'])
@@ -74,6 +74,8 @@
conf.load('coverage')
+ conf.load('sanitizers')
+
conf.define('DEFAULT_CONFIG_FILE', '%s/ndn/nlsr.conf' % conf.env['SYSCONFDIR'])
conf.write_config_header('config.hpp')
@@ -94,8 +96,7 @@
int(VERSION_SPLIT[2]),
VERSION_MAJOR=VERSION_SPLIT[0],
VERSION_MINOR=VERSION_SPLIT[1],
- VERSION_PATCH=VERSION_SPLIT[2],
- )
+ VERSION_PATCH=VERSION_SPLIT[2])
nlsr_objects = bld(
target='nlsr-objects',
@@ -105,28 +106,24 @@
excl=['src/main.cpp']),
use='NDN_CXX BOOST LOG4CXX SYNC',
includes='. src',
- export_includes='. src',
- )
+ export_includes='. src')
nlsr = bld(
target='bin/nlsr',
features='cxx cxxprogram',
source='src/main.cpp',
- use='nlsr-objects',
- )
+ use='nlsr-objects')
nlsrc = bld(
target='bin/nlsrc',
features='cxx cxxprogram',
source='tools/nlsrc.cpp',
- use='nlsr-objects BOOST',
- )
+ use='nlsr-objects BOOST')
bld(features="subst",
source='nlsr.conf',
target='nlsr.conf.sample',
- install_path="${SYSCONFDIR}/ndn",
- )
+ install_path="${SYSCONFDIR}/ndn")
if bld.env['WITH_TESTS']:
bld.recurse('tests')
@@ -149,14 +146,13 @@
version(bld)
if not bld.env.DOXYGEN:
- Logs.error("ERROR: cannot build documentation (`doxygen' is not found in $PATH)")
+ Logs.error("ERROR: cannot build documentation (`doxygen' not found in $PATH)")
else:
bld(features="subst",
name="doxygen-conf",
source="docs/doxygen.conf.in",
target="docs/doxygen.conf",
- VERSION=VERSION_BASE,
- )
+ VERSION=VERSION_BASE)
bld(features="doxygen",
doxyfile='docs/doxygen.conf',
@@ -166,7 +162,7 @@
version(bld)
if not bld.env.SPHINX_BUILD:
- bld.fatal("ERROR: cannot build documentation (`sphinx-build' is not found in $PATH)")
+ bld.fatal("ERROR: cannot build documentation (`sphinx-build' not found in $PATH)")
else:
bld(features="sphinx",
outdir="docs",