Exclude UBSan minimal runtime

Bug: 265157700
Test: Unit tests, manual verification
Change-Id: I149572fdc556f2f003127fa42a42d6fd387aa52d
diff --git a/BUILD.bazel b/BUILD.bazel
index f6778f3..8e9fae1 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -27,6 +27,8 @@
     "device_compatibility_flags_non_darwin",
     "device_compatibility_flags_non_windows",
     "generated_config_constants",
+    "libclang_rt_prebuilt_map",
+    "libclang_ubsan_minimal_rt_prebuilt_map",
     "variant_name",
     "x86_64_host_toolchains",
     "x86_64_musl_host_toolchains",
@@ -65,24 +67,6 @@
     ],
 )
 
-_LIBCLANG_RT_PREFIX = "%s/lib64/clang/%s/lib/linux" % (
-    generated_config_constants.CLANG_DEFAULT_VERSION,
-    generated_config_constants.CLANG_DEFAULT_SHORT_VERSION,
-)
-
-_LIBCLANG_RT_PREBUILT_MAP = {
-    "//build/bazel/platforms/os_arch:android_arm": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-arm-android.a",
-    "//build/bazel/platforms/os_arch:android_arm64": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-aarch64-android.a",
-    "//build/bazel/platforms/os_arch:android_x86": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-i686-android.a",
-    "//build/bazel/platforms/os_arch:android_x86_64": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-x86_64-android.a",
-    "//build/bazel/platforms/os_arch:linux_bionic_x86_64": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-x86_64-android.a",
-    "//build/bazel/platforms/os_arch:linux_glibc_x86": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-i386.a",
-    "//build/bazel/platforms/os_arch:linux_glibc_x86_64": _LIBCLANG_RT_PREFIX + "/libclang_rt.builtins-x86_64.a",
-    "//build/bazel/platforms/os_arch:linux_musl_x86": _LIBCLANG_RT_PREFIX + "/i686-unknown-linux-musl/lib/linux/libclang_rt.builtins-i386.a",
-    "//build/bazel/platforms/os_arch:linux_musl_x86_64": _LIBCLANG_RT_PREFIX + "/x86_64-unknown-linux-musl/lib/linux/libclang_rt.builtins-x86_64.a",
-    "//conditions:default": None,
-}
-
 # x86_64 toolchain definitions
 [
     android_cc_toolchain(
@@ -90,7 +74,8 @@
         clang_version = ":clang",
         clang_version_directory = generated_config_constants.CLANG_DEFAULT_VERSION,
         crt = _bionic_crt,
-        libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:android_x86_64"],
+        libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_x86_64"],
+        libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_x86_64"],
         linker_flags = generated_config_constants.X86_64ToolchainLdflags + generated_config_constants.X86_64Lldflags,
         target_arch = arches.X86_64,
         target_flags = generated_config_constants.X86_64ToolchainCflags +
@@ -113,7 +98,8 @@
         clang_version = ":clang",
         clang_version_directory = generated_config_constants.CLANG_DEFAULT_VERSION,
         crt = _bionic_crt,
-        libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:android_x86"],
+        libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_x86"],
+        libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_x86"],
         linker_flags = generated_config_constants.X86ToolchainLdflags + generated_config_constants.X86Lldflags,
         target_arch = arches.X86,
         target_flags = generated_config_constants.X86ToolchainCflags +
@@ -136,7 +122,8 @@
         clang_version = ":clang",
         clang_version_directory = generated_config_constants.CLANG_DEFAULT_VERSION,
         crt = _bionic_crt,
-        libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:android_arm64"],
+        libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_arm64"],
+        libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_arm64"],
         linker_flags = generated_config_constants.Arm64CpuVariantLdflags.get(
             variant.cpu_variant,
             [],
@@ -161,7 +148,8 @@
         clang_version = ":clang",
         clang_version_directory = generated_config_constants.CLANG_DEFAULT_VERSION,
         crt = _bionic_crt,
-        libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:android_arm"],
+        libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_arm"],
+        libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:android_arm"],
         linker_flags = generated_config_constants.ArmLldflags + arm_extra_ldflags(variant),
         target_arch = arches.Arm,
         target_flags = generated_config_constants.ArmCflags +
@@ -192,7 +180,8 @@
     ],
     crt = False,
     gcc_toolchain = generated_config_constants.LinuxGccRoot,
-    libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:linux_glibc_x86_64"],
+    libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_glibc_x86_64"],
+    libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_glibc_x86_64"],
     linker_flags = generated_config_constants.LinuxGlibcLdflags +
                    generated_config_constants.LinuxLdflags +
                    generated_config_constants.LinuxX8664Ldflags +
@@ -219,7 +208,8 @@
     ],
     crt = False,
     gcc_toolchain = generated_config_constants.LinuxGccRoot,
-    libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:linux_glibc_x86"],
+    libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_glibc_x86"],
+    libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_glibc_x86"],
     linker_flags = generated_config_constants.LinuxGlibcLdflags +
                    generated_config_constants.LinuxLdflags +
                    generated_config_constants.LinuxX86Ldflags +
@@ -246,7 +236,8 @@
     ],
     crt = _musl_crt,
     gcc_toolchain = generated_config_constants.LinuxGccRoot,
-    libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:linux_musl_x86_64"],
+    libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_musl_x86_64"],
+    libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_musl_x86_64"],
     linker_flags = generated_config_constants.LinuxMuslLdflags +
                    generated_config_constants.LinuxLdflags +
                    generated_config_constants.LinuxX8664Ldflags,
@@ -271,7 +262,8 @@
     ],
     crt = _musl_crt,
     gcc_toolchain = generated_config_constants.LinuxGccRoot,
-    libclang_rt_builtin = _LIBCLANG_RT_PREBUILT_MAP["//build/bazel/platforms/os_arch:linux_musl_x86"],
+    libclang_rt_builtin = libclang_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_musl_x86"],
+    libclang_rt_ubsan_minimal = libclang_ubsan_minimal_rt_prebuilt_map["//build/bazel/platforms/os_arch:linux_musl_x86"],
     linker_flags = generated_config_constants.LinuxMuslLdflags +
                    generated_config_constants.LinuxLdflags +
                    generated_config_constants.LinuxX86Ldflags,
@@ -373,7 +365,7 @@
 
 cc_import(
     name = "libclang_rt",
-    static_library = select(_LIBCLANG_RT_PREBUILT_MAP),
+    static_library = select(libclang_rt_prebuilt_map),
 )
 
 [alias(
diff --git a/cc_toolchain_config.bzl b/cc_toolchain_config.bzl
index 6da7520..daac2e3 100644
--- a/cc_toolchain_config.bzl
+++ b/cc_toolchain_config.bzl
@@ -265,6 +265,7 @@
         "compiler_flags": attr.string_list(default = []),
         "linker_flags": attr.string_list(default = []),
         "libclang_rt_builtin": attr.label(allow_single_file = True),
+        "libclang_rt_ubsan_minimal": attr.label(allow_single_file = True),
         # crtbegin and crtend libraries for compiling cc_library_shared and
         # cc_binary against the Bionic runtime
         "shared_library_crtbegin": attr.label(allow_single_file = True, cfg = "target"),
@@ -318,6 +319,7 @@
         # If false, the crt version and "normal" version of this toolchain are identical.
         crt = None,
         libclang_rt_builtin = None,
+        libclang_rt_ubsan_minimal = None,
         target_flags = [],
         compiler_flags = [],
         linker_flags = [],
@@ -328,6 +330,9 @@
     if libclang_rt_builtin:
         libclang_rt_path = libclang_rt_builtin
         extra_linker_paths.append(":" + libclang_rt_path)
+    libclang_rt_ubsan_minimal_path = None
+    if libclang_rt_ubsan_minimal:
+        libclang_rt_ubsan_minimal_path = libclang_rt_ubsan_minimal
     if gcc_toolchain:
         gcc_toolchain_path = "//%s:tools" % gcc_toolchain
         extra_linker_paths.append(gcc_toolchain_path)
@@ -338,6 +343,7 @@
             ("target_arch", target_arch),
             ("clang_version", clang_version),
             ("libclang_rt_builtin", libclang_rt_path),
+            ("libclang_rt_ubsan_minimal", libclang_rt_ubsan_minimal_path),
             ("target_flags", target_flags),
             ("compiler_flags", compiler_flags),
             ("linker_flags", linker_flags),
diff --git a/cc_toolchain_constants.bzl b/cc_toolchain_constants.bzl
index b6b70cfd..7dcc6eb 100644
--- a/cc_toolchain_constants.bzl
+++ b/cc_toolchain_constants.bzl
@@ -245,3 +245,34 @@
     ("cc_toolchain_x86_linux_musl_host", "@bazel_tools//tools/cpp:toolchain_type"),
     ("cc_toolchain_x86_linux_musl_host_nocrt", "nocrt_toolchain"),
 ]
+
+_libclang_rt_prefix = "%s/lib64/clang/%s/lib/linux" % (
+    generated_config_constants.CLANG_DEFAULT_VERSION,
+    generated_config_constants.CLANG_DEFAULT_SHORT_VERSION,
+)
+
+libclang_rt_prebuilt_map = {
+    "//build/bazel/platforms/os_arch:android_arm": _libclang_rt_prefix + "/libclang_rt.builtins-arm-android.a",
+    "//build/bazel/platforms/os_arch:android_arm64": _libclang_rt_prefix + "/libclang_rt.builtins-aarch64-android.a",
+    "//build/bazel/platforms/os_arch:android_x86": _libclang_rt_prefix + "/libclang_rt.builtins-i686-android.a",
+    "//build/bazel/platforms/os_arch:android_x86_64": _libclang_rt_prefix + "/libclang_rt.builtins-x86_64-android.a",
+    "//build/bazel/platforms/os_arch:linux_bionic_x86_64": _libclang_rt_prefix + "/libclang_rt.builtins-x86_64-android.a",
+    "//build/bazel/platforms/os_arch:linux_glibc_x86": _libclang_rt_prefix + "/libclang_rt.builtins-i386.a",
+    "//build/bazel/platforms/os_arch:linux_glibc_x86_64": _libclang_rt_prefix + "/libclang_rt.builtins-x86_64.a",
+    "//build/bazel/platforms/os_arch:linux_musl_x86": _libclang_rt_prefix + "/i686-unknown-linux-musl/lib/linux/libclang_rt.builtins-i386.a",
+    "//build/bazel/platforms/os_arch:linux_musl_x86_64": _libclang_rt_prefix + "/x86_64-unknown-linux-musl/lib/linux/libclang_rt.builtins-x86_64.a",
+    "//conditions:default": None,
+}
+
+libclang_ubsan_minimal_rt_prebuilt_map = {
+    "//build/bazel/platforms/os_arch:android_arm": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-arm-android.a",
+    "//build/bazel/platforms/os_arch:android_arm64": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-aarch64-android.a",
+    "//build/bazel/platforms/os_arch:android_x86": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-i686-android.a",
+    "//build/bazel/platforms/os_arch:android_x86_64": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-x86_64-android.a",
+    "//build/bazel/platforms/os_arch:linux_bionic_x86_64": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-x86_64-android.a",
+    "//build/bazel/platforms/os_arch:linux_glibc_x86": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-i386.a",
+    "//build/bazel/platforms/os_arch:linux_glibc_x86_64": _libclang_rt_prefix + "/libclang_rt.ubsan_minimal-x86_64.a",
+    "//build/bazel/platforms/os_arch:linux_musl_x86": _libclang_rt_prefix + "/i686-unknown-linux-musl/lib/linux/libclang_rt.ubsan_minimal-i386.a",
+    "//build/bazel/platforms/os_arch:linux_musl_x86_64": _libclang_rt_prefix + "/x86_64-unknown-linux-musl/lib/linux/libclang_rt.ubsan_minimal-x86_64.a",
+    "//conditions:default": None,
+}
diff --git a/cc_toolchain_features.bzl b/cc_toolchain_features.bzl
index 3074d4d..842fca1 100644
--- a/cc_toolchain_features.bzl
+++ b/cc_toolchain_features.bzl
@@ -1638,10 +1638,19 @@
         _generated_sanitizer_constants.HostOnlySanitizeFlags,
     )
 
+def _exclude_ubsan_rt_feature(path):
+    if not path:
+        return None
+    return _ubsan_flag_feature(
+        "ubsan_exclude_rt",
+        _actions.link,
+        ["-Wl,--exclude-libs=" + path.path],
+    )
+
 int_overflow_ignorelist_path = "build/soong/cc/config"
 int_overflow_ignorelist_filename = "integer_overflow_blocklist.txt"
 
-def _get_ubsan_features(target_os):
+def _get_ubsan_features(target_os, libclang_rt_ubsan_minimal):
     ALL_UBSAN_ACTIONS = _actions.compile + _actions.link + _actions.assemble
 
     ubsan_features = [
@@ -1876,7 +1885,10 @@
         ),
     ]
 
-    ubsan_features += [_host_or_device_specific_ubsan_feature(target_os)]
+    ubsan_features += [
+        _host_or_device_specific_ubsan_feature(target_os),
+        _exclude_ubsan_rt_feature(libclang_rt_ubsan_minimal),
+    ]
 
     return ubsan_features
 
@@ -1891,6 +1903,7 @@
     compile_only_flags = ctx.attr.compiler_flags
     linker_only_flags = ctx.attr.linker_flags
     libclang_rt_builtin = ctx.file.libclang_rt_builtin
+    libclang_rt_ubsan_minimal = ctx.file.libclang_rt_ubsan_minimal
     rtti_toggle = ctx.attr.rtti_toggle
 
     os_is_device = is_os_device(target_os)
@@ -1942,7 +1955,7 @@
         # Optimization
         _get_thinlto_features(),
         # Sanitizers
-        _get_ubsan_features(target_os),
+        _get_ubsan_features(target_os, libclang_rt_ubsan_minimal),
         # This must always come last.
         _link_crtend(crt_files),
     ]
diff --git a/cc_toolchain_features_ubsan_test.bzl b/cc_toolchain_features_ubsan_test.bzl
index d35cdc3..b0de66e 100644
--- a/cc_toolchain_features_ubsan_test.bzl
+++ b/cc_toolchain_features_ubsan_test.bzl
@@ -13,6 +13,7 @@
 limitations under the License.
 """
 
+load("@bazel_skylib//lib:paths.bzl", "paths")
 load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
 load(
     "//build/bazel/rules/test_common:flags.bzl",
@@ -20,6 +21,10 @@
     "action_flags_present_only_for_mnemonic_test",
 )
 load(
+    ":cc_toolchain_constants.bzl",
+    "libclang_ubsan_minimal_rt_prebuilt_map",
+)
+load(
     ":cc_toolchain_features.bzl",
     "int_overflow_ignorelist_filename",
     "int_overflow_ignorelist_path",
@@ -642,6 +647,89 @@
 
     return test_names
 
+_exclude_ubsan_rt_name = "ubsan_exclude_rt"
+
+def _exclude_ubsan_rt_test_for_os_arch(os_arch_platform, os, arch):
+    test_name = "%s_%s_test" % (
+        _exclude_ubsan_rt_name,
+        os_arch_platform.split(":")[-1],
+    )
+
+    action_flags_present_only_for_mnemonic_test(
+        name = test_name,
+        target_under_test = _exclude_ubsan_rt_name,
+        mnemonics = [link_action_mnemonic],
+        expected_flags = [
+            (
+                "-Wl,--exclude-libs=%s" %
+                paths.join(
+                    "prebuilts/clang/host/linux-x86",
+                    libclang_ubsan_minimal_rt_prebuilt_map[os_arch_platform],
+                )
+            ),
+        ],
+        target_compatible_with = [os, arch],
+    )
+
+    return test_name
+
+def _test_exclude_ubsan_rt():
+    native.cc_binary(
+        name = _exclude_ubsan_rt_name,
+        srcs = test_srcs,
+        features = ["ubsan_undefined"],
+        tags = ["manual"],
+    )
+
+    test_names = []
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:android_arm",
+        "//build/bazel/platforms/os:android",
+        "//build/bazel/platforms/arch:arm",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:android_arm64",
+        "//build/bazel/platforms/os:android",
+        "//build/bazel/platforms/arch:arm64",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:android_x86",
+        "//build/bazel/platforms/os:android",
+        "//build/bazel/platforms/arch:x86",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:android_x86_64",
+        "//build/bazel/platforms/os:android",
+        "//build/bazel/platforms/arch:x86_64",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
+        "//build/bazel/platforms/os:linux_bionic",
+        "//build/bazel/platforms/arch:x86_64",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:linux_glibc_x86",
+        "//build/bazel/platforms/os:linux",
+        "//build/bazel/platforms/arch:x86",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
+        "//build/bazel/platforms/os:linux",
+        "//build/bazel/platforms/arch:x86_64",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:linux_musl_x86",
+        "//build/bazel/platforms/os:linux_musl",
+        "//build/bazel/platforms/arch:x86",
+    )]
+    test_names += [_exclude_ubsan_rt_test_for_os_arch(
+        "//build/bazel/platforms/os_arch:linux_musl_x86_64",
+        "//build/bazel/platforms/os:linux_musl",
+        "//build/bazel/platforms/arch:x86_64",
+    )]
+
+    return test_names
+
 def cc_toolchain_features_ubsan_test_suite(name):
     individual_tests = [
         _test_ubsan_misc_undefined_feature(),
@@ -666,5 +754,6 @@
                 _test_ubsan_integer_overflow_feature() +
                 _test_host_only_features() +
                 _test_device_only_features() +
-                _test_device_only_and_host_only_features_absent_when_ubsan_disabled(),
+                _test_device_only_and_host_only_features_absent_when_ubsan_disabled() +
+                _test_exclude_ubsan_rt(),
     )