added actual support for running clang with sanitizers
diff --git a/aos/build/aos.gypi b/aos/build/aos.gypi
index 917a8ca..334a5e3 100644
--- a/aos/build/aos.gypi
+++ b/aos/build/aos.gypi
@@ -63,27 +63,41 @@
['CC', '/opt/clang-3.5/bin/clang'],
['CXX', '/opt/clang-3.5/bin/clang++'],
],
+ },
+ ], ['PLATFORM=="linux-amd64-gcc"', {
+ },
+ ], ['SANITIZER!="none"', {
'target_defaults': {
'cflags': [
- # TODO(brians): Always build with this in debug mode?
- #'-fsanitize=address',
-
+ '-fsanitize=<(SANITIZER)',
# TODO(brians): Figure out how to blacklist some bits of other
# people's code (ie stdlibc++...) and then have it abort on failure.
#'-fsanitize=undefined,integer',
-
- # TODO(brians): Try and figure out how to get these 2 to work (it
- # looks like they force using shared libraries which means building
- # everything with -fPIC).
- #'-fsanitize=memory',
- #'-fsanitize=thread',
],
'ldflags': [
- #'-fsanitize=thread',
+ '-fsanitize=<(SANITIZER)',
],
},
},
- ], ['PLATFORM=="linux-amd64-gcc"', {
+ ], ['SANITIZER_FPIC!=""', {
+ 'target_defaults': {
+ 'cflags': [
+ '-fPIC',
+ ],
+ 'ldflags': [
+ '-fPIC',
+ ],
+ },
+ },
+ ], ['SANITIZER=="memory"', {
+ 'target_defaults': {
+ 'cflags': [
+ '-fsanitize-memory-track-origins',
+ ],
+ 'ldflags': [
+ '-fsanitize-memory-track-origins',
+ ],
+ },
},
],
],
@@ -261,6 +275,9 @@
'cflags': [
'-Wunused-local-typedefs',
],
+ 'defines': [
+ '__has_feature(n)=0'
+ ],
},
], ['COMPILER=="clang"', {
'cflags': [
diff --git a/aos/build/build.py b/aos/build/build.py
index b954379..208b380 100755
--- a/aos/build/build.py
+++ b/aos/build/build.py
@@ -122,19 +122,21 @@
class PrimeProcessor(Processor):
class Platform(Processor.Platform):
- def __init__(self, architecture, compiler, debug):
+ def __init__(self, architecture, compiler, debug, sanitizer):
super(PrimeProcessor.Platform, self).__init__()
self.architecture = architecture
self.compiler = compiler
self.debug = debug
+ self.sanitizer = sanitizer
def __repr__(self):
- return 'PrimeProcessor.Platform(architecture=%s, compiler=%s, debug=%s)' \
- % (self.architecture, self.compiler, self.debug)
+ return 'PrimeProcessor.Platform(architecture=%s, compiler=%s, debug=%s' \
+ ', sanitizer=%s)' \
+ % (self.architecture, self.compiler, self.debug, self.sanitizer)
def __str__(self):
- return '%s-%s%s' % (self.architecture, self.compiler,
- '-debug' if self.debug else '')
+ return '%s-%s%s-%s' % (self.architecture, self.compiler,
+ '-debug' if self.debug else '', self.sanitizer)
def os(self):
return 'linux'
@@ -182,12 +184,19 @@
r = {}
if self.compiler == 'clang':
r['LD_LIBRARY_PATH'] = '/opt/clang-3.5/lib64'
+ if self.sanitizer == 'address':
r['ASAN_SYMBOLIZER_PATH'] = '/opt/clang-3.5/bin/llvm-symbolizer'
r['ASAN_OPTIONS'] = 'detect_leaks=1:check_initialization_order=1:strict_init_order=1'
+ elif self.sanitizer == 'memory':
+ r['MSAN_SYMBOLIZER_PATH'] = '/opt/clang-3.5/bin/llvm-symbolizer'
return r
ARCHITECTURES = ['arm', 'amd64']
COMPILERS = ['clang', 'gcc']
+ # TODO(brians): memory doesn't really work because we don't have everything
+ # instrumented. Print out a warning or something.
+ SANITIZERS = ['address', 'undefined', 'integer', 'memory', 'thread', 'none']
+ PIC_SANITIZERS = ['memory', 'thread']
def __init__(self, is_test, is_deploy):
super(Processor, self).__init__()
@@ -197,7 +206,11 @@
for compiler in PrimeProcessor.COMPILERS:
for debug in [True, False]:
platforms.append(
- PrimeProcessor.Platform(architecture, compiler, debug))
+ PrimeProcessor.Platform(architecture, compiler, debug, 'none'))
+ for sanitizer in PrimeProcessor.SANITIZERS:
+ if sanitizer != 'none':
+ platforms.append(
+ PrimeProcessor.Platform('amd64', 'clang', True, sanitizer))
self.platforms = frozenset(platforms)
if is_test:
self.default_platforms = self.select_platforms(architecture='amd64',
@@ -232,18 +245,19 @@
r = selected
return r
- def select_platforms(self, architecture=None, compiler=None, debug=None):
+ def select_platforms(self, architecture=None, compiler=None, debug=None, sanitizer=None):
r = []
for platform in self.platforms:
if architecture is None or platform.architecture == architecture:
if compiler is None or platform.compiler == compiler:
if debug is None or platform.debug == debug:
- r.append(platform)
+ if sanitizer is None or platform.sanitizer == sanitizer:
+ r.append(platform)
return set(r)
def select_platforms_string(self, string):
r = []
- architecture, compiler, debug = None, None, None
+ architecture, compiler, debug, sanitizer = None, None, None, None
for part in string.split('-'):
if part in PrimeProcessor.ARCHITECTURES:
architecture = part
@@ -253,12 +267,15 @@
debug = True
elif part in ['release', 'nodebug', 'ndb']:
debug = False
+ elif part in PrimeProcessor.SANITIZERS:
+ sanitizer = part
else:
raise Processor.UnknownPlatform('Unknown platform string component "%s".' % part)
return self.select_platforms(
architecture=architecture,
compiler=compiler,
- debug=debug)
+ debug=debug,
+ sanitizer=sanitizer)
def check_installed(self):
self.do_check_installed(
@@ -363,9 +380,17 @@
if processor.is_crio():
download_externals('crio')
else:
+ to_download = set()
for architecture in PrimeProcessor.ARCHITECTURES:
- if platforms & processor.select_platforms(architecture=architecture):
- download_externals(architecture)
+ for sanitizer in PrimeProcessor.PIC_SANITIZERS:
+ if platforms & processor.select_platforms(architecture=architecture,
+ sanitizer=sanitizer):
+ to_download.add(architecture + '-fPIC')
+ if platforms & processor.select_platforms(architecture=architecture,
+ sanitizer='none'):
+ to_download.add(architecture)
+ for download_target in to_download:
+ download_externals(download_target)
class ToolsConfig(object):
def __init__(self):
@@ -394,6 +419,8 @@
raise excinfo[1]
def need_to_run_gyp(platform):
+ if not os.path.exists(platform.build_ninja()):
+ return True
dirs = os.listdir(os.path.join(aos_path(), '..'))
# Looking through these folders takes a long time and isn't useful.
dirs.remove('output')
@@ -430,7 +457,11 @@
'-DPLATFORM=%s' % platform.gyp_platform(),
'-DARCHITECTURE=%s' % platform.architecture,
'-DCOMPILER=%s' % platform.compiler,
- '-DDEBUG=%s' % ('yes' if platform.debug else 'no')) +
+ '-DDEBUG=%s' % ('yes' if platform.debug else 'no'),
+ '-DSANITIZER=%s' % platform.sanitizer,
+ '-DSANITIZER_FPIC=%s' % ('-fPIC'
+ if platform.sanitizer in PrimeProcessor.PIC_SANITIZERS
+ else '')) +
processor.extra_gyp_flags() + (args.main_gyp,),
stdin=subprocess.PIPE)
gyp.communicate(("""
diff --git a/aos/build/download_externals.sh b/aos/build/download_externals.sh
index e643107..61e7b7d 100755
--- a/aos/build/download_externals.sh
+++ b/aos/build/download_externals.sh
@@ -23,10 +23,14 @@
IS_CRIO=0
elif [ "$1" == "amd64" ]; then
COMPILED=${EXTERNALS}/../compiled-amd64
+ IS_CRIO=0
+elif [ "$1" == "amd64-fPIC" ]; then
+ COMPILED=${EXTERNALS}/../compiled-amd64-fPIC
- export CFLAGS="-march=atom -mfpmath=sse"
- export CXXFLAGS="-march=atom -mfpmath=sse"
- CONFIGURE_FLAGS="CFLAGS=\"${CFLAGS}\" CXXFLAGS=\"${CXXFLAGS}\""
+ export CFLAGS="-fPIC"
+ export CXXFLAGS="-fPIC"
+ export LDFLAGS="-fPIC"
+ CONFIGURE_FLAGS="CFLAGS=\"${CFLAGS}\" CXXFLAGS=\"${CXXFLAGS}\" LDFLAGS=\"${LDFLAGS}\""
IS_CRIO=0
elif [ "$1" == "crio" ]; then
IS_CRIO=1
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
index 27c2512..ec7a2a1 100644
--- a/aos/build/externals.gyp
+++ b/aos/build/externals.gyp
@@ -5,8 +5,8 @@
# TODO(brians): Would we not have to do this hackery if we named it externals_path etc?
'externals': '<(AOS)/../output/downloaded',
'externals_abs': '<!(readlink -f ../../output/downloaded)',
- 'compiled': '<(externals)/../compiled-<(ARCHITECTURE)',
- 'compiled_abs': '<(externals_abs)/../compiled-<(ARCHITECTURE)',
+ 'compiled': '<(externals)/../compiled-<(ARCHITECTURE)<(SANITIZER_FPIC)',
+ 'compiled_abs': '<(externals_abs)/../compiled-<(ARCHITECTURE)<(SANITIZER_FPIC)',
# These versions have to be kept in sync with the ones in download_externals.sh.
'eigen_version': '3.2.1',