From abae5ca3e8142f93cf0c2597e3410ed955c4dd59 Mon Sep 17 00:00:00 2001 From: Oliver Lee Date: Wed, 11 Jan 2023 01:34:48 -0800 Subject: [PATCH] Add sanitizer features to unix_cc_toolchain_config There was some discussion here about adding `asan`, `tsan`, and `ubsan` features to the unix toolchains to match macos. https://github.com/grailbio/bazel-toolchain/issues/90#issuecomment-1205804096 I've taken my changes local to that project and copied it into Bazel as suggested by @fmeum. I've written some tests but I'm not sure where to place them or if it makes sense to depend on the error messages from asan/tsan/ubsan. Closes #17083. PiperOrigin-RevId: 501213060 Change-Id: I9d973ebe35e4fa2804d2e91df9f700a285f7b404 --- src/test/shell/bazel/cc_integration_test.sh | 105 ++++++++++++++++++++ tools/cpp/unix_cc_toolchain_config.bzl | 66 ++++++++++++ 2 files changed, 171 insertions(+) diff --git a/src/test/shell/bazel/cc_integration_test.sh b/src/test/shell/bazel/cc_integration_test.sh index f411a15f1f16aa..e4e2ae752d5ab5 100755 --- a/src/test/shell/bazel/cc_integration_test.sh +++ b/src/test/shell/bazel/cc_integration_test.sh @@ -1856,4 +1856,109 @@ EOF fi } +# sanitizer features are opt-in so we check if the sanitizer library is +# installed and skip the test if it isn't (e.g. centos-7-openjdk-11-gcc-10) +function __is_installed() { + local lib="$1" + + if [[ "$(uname -s | tr 'A-Z' 'a-z')" == "linux" ]]; then + return $(ldconfig -p | grep -q "$lib") + fi + + # assume installed for darwin +} + +function test_cc_toolchain_asan_feature() { + local feature=asan + __is_installed "lib$feature" || return 0 + + mkdir pkg + cat > pkg/BUILD < pkg/example.cc < "$TEST_log" && fail "Should have failed due to $feature" || true + expect_log "ERROR: AddressSanitizer: stack-use-after-scope" +} + +function test_cc_toolchain_tsan_feature() { + local feature=tsan + __is_installed "lib$feature" || return 0 + + mkdir pkg + cat > pkg/BUILD < pkg/example.cc < + +int value = 0; + +void increment() { + ++value; +} + +int main() { + std::thread t1(increment); + std::thread t2(increment); + t1.join(); + t2.join(); + + return value; +} +EOF + + bazel run //pkg:example &> "$TEST_log" && fail "Should have failed due to $feature" || true + expect_log "WARNING: ThreadSanitizer: data race" +} + +function test_cc_toolchain_ubsan_feature() { + local feature=ubsan + __is_installed "lib$feature" || return 0 + + mkdir pkg + cat > pkg/BUILD < pkg/example.cc < "$TEST_log" && fail "Should have failed due to $feature" || true + expect_log "runtime error: index 10 out of bounds" +} + run_suite "cc_integration_test" diff --git a/tools/cpp/unix_cc_toolchain_config.bzl b/tools/cpp/unix_cc_toolchain_config.bzl index b6e4dcdd2fca12..64e8f0c95ebb76 100644 --- a/tools/cpp/unix_cc_toolchain_config.bzl +++ b/tools/cpp/unix_cc_toolchain_config.bzl @@ -143,6 +143,35 @@ lto_index_actions = [ ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ] +def _sanitizer_feature(name = "", specific_compile_flags = [], specific_link_flags = []): + return feature( + name = name, + flag_sets = [ + flag_set( + actions = all_compile_actions, + flag_groups = [ + flag_group(flags = [ + "-O1", + "-fno-omit-frame-pointer", + "-fno-sanitize-recover=all", + ] + specific_compile_flags), + ], + with_features = [ + with_feature_set(features = [name]), + ], + ), + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group(flags = specific_link_flags), + ], + with_features = [ + with_feature_set(features = [name]), + ], + ), + ], + ) + def _impl(ctx): tool_paths = [ tool_path(name = name, path = path) @@ -1215,6 +1244,37 @@ def _impl(ctx): enabled = True, ) + asan_feature = _sanitizer_feature( + name = "asan", + specific_compile_flags = [ + "-fsanitize=address", + "-fno-common", + ], + specific_link_flags = [ + "-fsanitize=address", + ], + ) + + tsan_feature = _sanitizer_feature( + name = "tsan", + specific_compile_flags = [ + "-fsanitize=thread", + ], + specific_link_flags = [ + "-fsanitize=thread", + ], + ) + + ubsan_feature = _sanitizer_feature( + name = "ubsan", + specific_compile_flags = [ + "-fsanitize=undefined", + ], + specific_link_flags = [ + "-fsanitize=undefined", + ], + ) + is_linux = ctx.attr.target_libc != "macosx" libtool_feature = feature( name = "libtool", @@ -1255,6 +1315,9 @@ def _impl(ctx): strip_debug_symbols_feature, coverage_feature, supports_pic_feature, + asan_feature, + tsan_feature, + ubsan_feature, ] + ( [ supports_start_end_lib_feature, @@ -1290,6 +1353,9 @@ def _impl(ctx): libtool_feature, archiver_flags_feature, supports_pic_feature, + asan_feature, + tsan_feature, + ubsan_feature, ] + ( [ supports_start_end_lib_feature,