diff --git a/Utilities/build-script-helper.py b/Utilities/build-script-helper.py index 2aa9e97f..05e1af99 100755 --- a/Utilities/build-script-helper.py +++ b/Utilities/build-script-helper.py @@ -30,6 +30,10 @@ def get_swiftpm_options(args): if args.verbose: swiftpm_args += ['--verbose'] + if args.sanitize: + for san in args.sanitize: + swiftpm_args += ['--sanitize=%s' % san] + if platform.system() == 'Darwin': swiftpm_args += [ # Relative library rpath for swift; will only be used when /usr/lib/swift @@ -81,39 +85,8 @@ def delete_rpath(rpath, binary): print(' '.join(cmd)) subprocess.check_call(cmd) -def main(): - parser = argparse.ArgumentParser(description='Build along with the Swift build-script.') - def add_common_args(parser): - parser.add_argument('--package-path', metavar='PATH', help='directory of the package to build', default='.') - parser.add_argument('--toolchain', required=True, metavar='PATH', help='build using the toolchain at PATH') - parser.add_argument('--ninja-bin', metavar='PATH', help='ninja binary to use for testing') - parser.add_argument('--build-path', metavar='PATH', default='.build', help='build in the given path') - parser.add_argument('--configuration', '-c', default='debug', help='build using configuration (release|debug)') - parser.add_argument('--no-local-deps', action='store_true', help='use normal remote dependencies when building') - parser.add_argument('--verbose', '-v', action='store_true', help='enable verbose output') - - subparsers = parser.add_subparsers(title='subcommands', dest='action', metavar='action') - build_parser = subparsers.add_parser('build', help='build the package') - add_common_args(build_parser) - - test_parser = subparsers.add_parser('test', help='test the package') - add_common_args(test_parser) - - install_parser = subparsers.add_parser('install', help='build the package') - add_common_args(install_parser) - - args = parser.parse_args(sys.argv[1:]) - - # Canonicalize paths - args.package_path = os.path.abspath(args.package_path) - args.build_path = os.path.abspath(args.build_path) - args.toolchain = os.path.abspath(args.toolchain) - - if args.toolchain: - swift_exec = os.path.join(args.toolchain, 'usr', 'bin', 'swift') - else: - swift_exec = 'swift' +def handle_invocation(swift_exec, args): swiftpm_args = get_swiftpm_options(args) env = os.environ @@ -126,6 +99,14 @@ def main(): if args.ninja_bin: env['NINJA_BIN'] = args.ninja_bin + if args.sanitize and 'address' in args.sanitize: + # Workaround reports in Foundation: https://bugs.swift.org/browse/SR-12551 + env['ASAN_OPTIONS'] = 'detect_leaks=false' + if args.sanitize and 'undefined' in args.sanitize: + supp = os.path.join(args.package_path, 'Utilities', 'ubsan_supressions.supp') + env['UBSAN_OPTIONS'] = 'halt_on_error=true,suppressions=%s' % supp + + if args.action == 'build': swiftpm('build', swift_exec, swiftpm_args, env) elif args.action == 'test': @@ -141,5 +122,66 @@ def main(): else: assert False, 'unknown action \'{}\''.format(args.action) + +def main(): + parser = argparse.ArgumentParser(description='Build along with the Swift build-script.') + def add_common_args(parser): + parser.add_argument('--package-path', metavar='PATH', help='directory of the package to build', default='.') + parser.add_argument('--toolchain', required=True, metavar='PATH', help='build using the toolchain at PATH') + parser.add_argument('--ninja-bin', metavar='PATH', help='ninja binary to use for testing') + parser.add_argument('--build-path', metavar='PATH', default='.build', help='build in the given path') + parser.add_argument('--configuration', '-c', default='debug', help='build using configuration (release|debug)') + parser.add_argument('--no-local-deps', action='store_true', help='use normal remote dependencies when building') + parser.add_argument('--sanitize', action='append', help='build using the given sanitizer(s) (address|thread|undefined)') + parser.add_argument('--sanitize-all', action='store_true', help='build using every available sanitizer in sub-directories of build path') + parser.add_argument('--verbose', '-v', action='store_true', help='enable verbose output') + + subparsers = parser.add_subparsers(title='subcommands', dest='action', metavar='action') + build_parser = subparsers.add_parser('build', help='build the package') + add_common_args(build_parser) + + test_parser = subparsers.add_parser('test', help='test the package') + add_common_args(test_parser) + + install_parser = subparsers.add_parser('install', help='build the package') + add_common_args(install_parser) + + args = parser.parse_args(sys.argv[1:]) + + if args.sanitize and args.sanitize_all: + assert False, 'cannot combine --sanitize with --sanitize-all' + + # Canonicalize paths + args.package_path = os.path.abspath(args.package_path) + args.build_path = os.path.abspath(args.build_path) + args.toolchain = os.path.abspath(args.toolchain) + + if args.toolchain: + swift_exec = os.path.join(args.toolchain, 'usr', 'bin', 'swift') + else: + swift_exec = 'swift' + + handle_invocation(swift_exec, args) + if args.sanitize_all: + base = args.build_path + + print('=== %s sourcekit-lsp with asan ===' % args.action) + args.sanitize = ['address'] + args.build_path = os.path.join(base, 'test-asan') + handle_invocation(swift_exec, args) + + print('=== %s sourcekit-lsp with tsan ===' % args.action) + args.sanitize = ['thread'] + args.build_path = os.path.join(base, 'test-tsan') + handle_invocation(swift_exec, args) + + # Linux ubsan disabled: https://bugs.swift.org/browse/SR-12550 + if platform.system() != 'Linux': + print('=== %s sourcekit-lsp with ubsan ===' % args.action) + args.sanitize = ['undefined'] + args.build_path = os.path.join(base, 'test-ubsan') + handle_invocation(swift_exec, args) + + if __name__ == '__main__': main() diff --git a/Utilities/ubsan_supressions.supp b/Utilities/ubsan_supressions.supp new file mode 100644 index 00000000..ee469b3b --- /dev/null +++ b/Utilities/ubsan_supressions.supp @@ -0,0 +1 @@ +alignment:mdb.c