Add CI toolchain verification tests.

This adds C++ preprocessor/runtime and ELF binary verification tests in `//ci` to validate the compiler (`clang`, `gcc`, `msvc`, `clang-cl`), C++ standard library (`libc++`, `libstdc++`, MSVC STL), exception handling mode, target architecture, and sanitizer instrumentation across our CI toolchains.

PiperOrigin-RevId: 999050499
diff --git a/.bazelrc b/.bazelrc
index fd7c3ef..8040621 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -30,7 +30,7 @@
 # Configure our Linux Docker toolchain setup.
 common --extra_toolchains=@docker_toolchain//:all
 build:linux --cxxopt=-std=c++17 --host_cxxopt=-std=c++17
-build:linux --copt=-fno-exceptions
+build:linux --copt=-fno-exceptions --//ci:exceptions=disabled
 build:linux --copt=-Werror
 build:linux --copt=-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1
 build:linux --features=external_include_paths
@@ -43,9 +43,10 @@
 build:windows-msvc --copt=/WX
 build:windows-msvc --per_file_copt=external/.*@/w
 build:windows-msvc --host_per_file_copt=external/.*@/w
+build:windows-msvc --//ci:compiler=msvc --//ci:stdlib=msvc --//ci:exceptions=enabled
 
 build:windows-clangcl --config=windows-msvc
-build:windows-clangcl --compiler=clang-cl
+build:windows-clangcl --compiler=clang-cl --//ci:compiler=clang-cl
 build:windows-clangcl --copt=-Wno-microsoft-cast
 build:windows-clangcl --extra_execution_platforms=//:x64_windows-clang-cl
 build:windows-clangcl --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl
@@ -57,27 +58,28 @@
 build:macos --features=external_include_paths
 build:macos --per_file_copt=external/.*@-w
 build:macos --host_per_file_copt=external/.*@-w
+build:macos --//ci:compiler=clang --//ci:stdlib=libc++ --//ci:exceptions=enabled
 
-build:gcc --config=linux --platforms=//ci:linux_gcc
-build:gcc-exceptions --config=gcc --copt=-fexceptions
-build:clang --config=linux --platforms=//ci:linux_clang --conlyopt=-Wno-unused-command-line-argument
-build:clang-exceptions --config=clang --copt=-fexceptions
-build:clang-arm --config=linux --platforms=//ci:linux_arm_clang --conlyopt=-Wno-unused-command-line-argument
-build:libstdc++ --config=clang --features=libstdc++ --copt=-march=haswell
+build:gcc --config=linux --platforms=//ci:linux_gcc --//ci:compiler=gcc --//ci:stdlib=libstdc++
+build:gcc-exceptions --config=gcc --copt=-fexceptions --//ci:exceptions=enabled
+build:clang --config=linux --platforms=//ci:linux_clang --conlyopt=-Wno-unused-command-line-argument --//ci:compiler=clang --//ci:stdlib=libc++
+build:clang-exceptions --config=clang --copt=-fexceptions --//ci:exceptions=enabled
+build:clang-arm --config=linux --platforms=//ci:linux_arm_clang --conlyopt=-Wno-unused-command-line-argument --//ci:compiler=clang --//ci:stdlib=libc++
+build:libstdc++ --config=clang --features=libstdc++ --copt=-march=haswell --//ci:stdlib=libstdc++
 
 # Sanitizer configurations.
-build:ubsan --features=ubsan
+build:ubsan --features=ubsan --//ci:sanitizer=ubsan
 build:ubsan --copt=-fsanitize=float-divide-by-zero,nullability,undefined
 build:ubsan --copt=-fno-sanitize-recover=float-divide-by-zero,nullability,undefined
 build:ubsan --copt=-fno-sanitize-blacklist
 test:ubsan --test_env=UBSAN_OPTIONS=print_stacktrace=1
 
-build:asan --config=clang --config=ubsan --features=asan
+build:asan --config=clang --config=ubsan --features=asan --//ci:sanitizer=asan
 build:asan --copt=-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG
 build:asan --linkopt=-fsanitize-link-c++-runtime
 test:asan --test_tag_filters=-benchmark,-noasan
 
-build:tsan --config=clang --features=tsan
+build:tsan --config=clang --features=tsan --//ci:sanitizer=tsan
 build:tsan --copt=-fno-sanitize-blacklist
 build:tsan --build_tag_filters=-notsan
 test:tsan --test_tag_filters=-benchmark,-notsan
diff --git a/MODULE.bazel b/MODULE.bazel
index d4096d2..0c70441 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -35,6 +35,11 @@
     version = "1.9.5",
     dev_dependency = True,
 )
+bazel_dep(
+    name = "rules_shell",
+    version = "0.6.1",
+    dev_dependency = True,
+)
 
 # Note: Googletest is NOT a dev_dependency. Some Abseil test utilities
 # intended to be used by Abseil users depend on GoogleTest.
diff --git a/ci/BUILD.bazel b/ci/BUILD.bazel
index c83d079..c1ece12 100644
--- a/ci/BUILD.bazel
+++ b/ci/BUILD.bazel
@@ -12,8 +12,97 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
+load("@rules_cc//cc:cc_test.bzl", "cc_test")
+load("@rules_shell//shell:sh_test.bzl", "sh_test")
+
 package(default_visibility = ["//visibility:private"])
 
+string_flag(
+    name = "compiler",
+    build_setting_default = "none",
+)
+
+config_setting(
+    name = "clang_compiler",
+    flag_values = {":compiler": "clang"},
+)
+
+config_setting(
+    name = "gcc_compiler",
+    flag_values = {":compiler": "gcc"},
+)
+
+config_setting(
+    name = "msvc_compiler",
+    flag_values = {":compiler": "msvc"},
+)
+
+config_setting(
+    name = "clang_cl_compiler",
+    flag_values = {":compiler": "clang-cl"},
+)
+
+string_flag(
+    name = "stdlib",
+    build_setting_default = "none",
+)
+
+config_setting(
+    name = "libcxx_enabled",
+    flag_values = {":stdlib": "libc++"},
+)
+
+config_setting(
+    name = "libstdcxx_enabled",
+    flag_values = {":stdlib": "libstdc++"},
+)
+
+config_setting(
+    name = "msvc_stdlib_enabled",
+    flag_values = {":stdlib": "msvc"},
+)
+
+string_flag(
+    name = "exceptions",
+    build_setting_default = "none",
+)
+
+config_setting(
+    name = "exceptions_enabled",
+    flag_values = {":exceptions": "enabled"},
+)
+
+config_setting(
+    name = "exceptions_disabled",
+    flag_values = {":exceptions": "disabled"},
+)
+
+string_flag(
+    name = "sanitizer",
+    build_setting_default = "none",
+)
+
+config_setting(
+    name = "asan_enabled",
+    flag_values = {":sanitizer": "asan"},
+)
+
+config_setting(
+    name = "tsan_enabled",
+    flag_values = {":sanitizer": "tsan"},
+)
+
+config_setting(
+    name = "msan_enabled",
+    flag_values = {":sanitizer": "msan"},
+)
+
+config_setting(
+    name = "ubsan_enabled",
+    flag_values = {":sanitizer": "ubsan"},
+)
+
 platform(
     name = "rbe",
     constraint_values = [
@@ -82,3 +171,241 @@
         "@bazel_tools//tools/cpp:clang",
     ],
 )
+
+# Verification of our CI toolchains.
+
+cc_test(
+    name = "toolchain_test",
+    srcs = ["toolchain_test.cc"],
+    local_defines = select({
+        ":clang_compiler": ["ABSL_CI_EXPECT_COMPILER_CLANG=1"],
+        ":gcc_compiler": ["ABSL_CI_EXPECT_COMPILER_GCC=1"],
+        ":msvc_compiler": ["ABSL_CI_EXPECT_COMPILER_MSVC=1"],
+        ":clang_cl_compiler": ["ABSL_CI_EXPECT_COMPILER_CLANG_CL=1"],
+        "//conditions:default": [],
+    }) + select({
+        ":libcxx_enabled": ["ABSL_CI_EXPECT_STDLIB_LIBCXX=1"],
+        ":libstdcxx_enabled": ["ABSL_CI_EXPECT_STDLIB_LIBSTDCXX=1"],
+        ":msvc_stdlib_enabled": ["ABSL_CI_EXPECT_STDLIB_MSVC=1"],
+        "//conditions:default": [],
+    }) + select({
+        ":exceptions_enabled": ["ABSL_CI_EXPECT_EXCEPTIONS_ENABLED=1"],
+        ":exceptions_disabled": ["ABSL_CI_EXPECT_EXCEPTIONS_DISABLED=1"],
+        "//conditions:default": [],
+    }) + select({
+        ":asan_enabled": ["ABSL_CI_EXPECT_SANITIZER_ASAN=1"],
+        ":tsan_enabled": ["ABSL_CI_EXPECT_SANITIZER_TSAN=1"],
+        ":msan_enabled": ["ABSL_CI_EXPECT_SANITIZER_MSAN=1"],
+        "//conditions:default": [],
+    }),
+)
+
+# Architecture verification tests
+sh_test(
+    name = "x86_64_architecture_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "arch",
+        "X86-64",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+        "@platforms//cpu:x86_64",
+    ],
+)
+
+sh_test(
+    name = "aarch64_architecture_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "arch",
+        "AArch64",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+        "@platforms//cpu:aarch64",
+    ],
+)
+
+# Compiler ELF .comment verification tests
+sh_test(
+    name = "clang_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "comment",
+        "clang version",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":clang_compiler": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+sh_test(
+    name = "gcc_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "comment",
+        "GCC:",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":gcc_compiler": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+# Standard library dynamic linkage verification tests
+sh_test(
+    name = "libstdcxx_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "needed",
+        "libstdc++.so",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":libstdcxx_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+sh_test(
+    name = "libstdcxx_not_needed_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "not_needed",
+        "libstdc++.so",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":libcxx_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+sh_test(
+    name = "libcxx_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "needed",
+        "libc++.so",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":libcxx_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }) + select({
+        # These sanitizers link libc++ statically.
+        ":msan_enabled": ["@platforms//:incompatible"],
+        ":tsan_enabled": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    }),
+)
+
+sh_test(
+    name = "libcxx_not_needed_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "not_needed",
+        "libc++.so",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":libstdcxx_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+# Sanitizer runtime instrumentation verification tests
+sh_test(
+    name = "asan_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "symbol",
+        "__asan",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":asan_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+sh_test(
+    name = "ubsan_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "symbol",
+        "__ubsan",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":asan_enabled": [],
+        ":ubsan_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+sh_test(
+    name = "msan_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "symbol",
+        "__msan",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":msan_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
+
+sh_test(
+    name = "tsan_verification_test",
+    srcs = ["verify_binary.sh"],
+    args = [
+        "$(rootpath :toolchain_test)",
+        "symbol",
+        "__tsan",
+    ],
+    data = [":toolchain_test"],
+    target_compatible_with = [
+        "@platforms//os:linux",
+    ] + select({
+        ":tsan_enabled": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)
diff --git a/ci/toolchain_test.cc b/ci/toolchain_test.cc
new file mode 100644
index 0000000..86cbcba
--- /dev/null
+++ b/ci/toolchain_test.cc
@@ -0,0 +1,147 @@
+// Copyright 2026 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstddef>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#if defined(ABSL_CI_EXPECT_COMPILER_CLANG)
+#if !defined(__clang__) || defined(_MSC_VER)
+#error "Expected Clang, but __clang__ is not defined or _MSC_VER is defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_COMPILER_GCC)
+#if !defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
+#error "Expected GCC, but __clang__ or _MSC_VER is defined or __GNUC__ is not"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_COMPILER_MSVC)
+#if !defined(_MSC_VER) || defined(__clang__)
+#error "Expected MSVC, but _MSC_VER is not defined or __clang__ is defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_COMPILER_CLANG_CL)
+#if !defined(_MSC_VER) || !defined(__clang__)
+#error "Expected clang-cl compiler, but _MSC_VER or __clang__ is not defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_STDLIB_LIBCXX)
+#if !defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) || \
+    defined(_MSVC_STL_UPDATE)
+#error "Expected libc++, but _LIBCPP_VERSION is not defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_STDLIB_LIBSTDCXX)
+#if !defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \
+    defined(_MSVC_STL_UPDATE)
+#error "Expected libstdc++, but __GLIBCXX__ is not defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_STDLIB_MSVC)
+#if !defined(_MSVC_STL_UPDATE) || defined(_LIBCPP_VERSION) || \
+    defined(__GLIBCXX__)
+#error "Expected MSVC STL, but _MSVC_STL_UPDATE is not defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_EXCEPTIONS_ENABLED)
+#if !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
+#error "Expected C++ exceptions, but __EXCEPTIONS and _CPPUNWIND are undefined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_EXCEPTIONS_DISABLED)
+#if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
+#error "Expected no C++ exceptions, but __EXCEPTIONS or _CPPUNWIND is defined"
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_SANITIZER_ASAN)
+#if !defined(__SANITIZE_ADDRESS__)
+#if !defined(__has_feature) || !__has_feature(address_sanitizer)
+#error "Expected AddressSanitizer to be enabled"
+#endif
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_SANITIZER_TSAN)
+#if !defined(__SANITIZE_THREAD__)
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+#error "Expected ThreadSanitizer to be enabled"
+#endif
+#endif
+#endif
+
+#if defined(ABSL_CI_EXPECT_SANITIZER_MSAN)
+#if !defined(__SANITIZE_MEMORY__)
+#if !defined(__has_feature) || !__has_feature(memory_sanitizer)
+#error "Expected MemorySanitizer to be enabled"
+#endif
+#endif
+#endif
+
+namespace {
+
+// Prevent the compiler from optimizing away memory access or sanitizer
+// instrumentation.
+#if defined(_MSC_VER) && !defined(__clang__)
+__declspec(noinline)
+#else
+__attribute__((noinline))
+#endif
+void TouchMemory(int* ptr) {
+  volatile int* vptr = ptr;
+  *vptr = 42;
+}
+
+}  // namespace
+
+int main(int argc, char** /*argv*/) {
+  // 1. Long string to bypass Short String Optimization (SSO) and exercise
+  // stdlib heap.
+  std::string s =
+      "abseil toolchain test with long string to bypass SSO allocation limit";
+  std::cout << s << '\n';
+
+  // 2. Dynamic heap allocation and pointer access to ensure ASAN/MSAN/TSAN
+  // hooks.
+  auto vec = std::make_unique<std::vector<int>>(100, 7);
+  TouchMemory(vec->data());
+
+  // 3. Volatile indexing and arithmetic to ensure UBSAN checks are retained.
+  volatile std::size_t idx = argc > 0 ? 0 : 1;
+  (*vec)[idx] += 1;
+
+#if defined(ABSL_CI_EXPECT_EXCEPTIONS_ENABLED)
+  bool caught = false;
+  try {
+    throw 42;
+  } catch (int v) {
+    caught = (v == 42);
+  }
+  if (!caught) {
+    return 1;
+  }
+#endif
+
+  return 0;
+}
diff --git a/ci/verify_binary.sh b/ci/verify_binary.sh
new file mode 100755
index 0000000..60700e4
--- /dev/null
+++ b/ci/verify_binary.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Copyright 2026 The Abseil Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Checks ELF header architecture, dynamic needed libraries, or binary symbol tables.
+set -euo pipefail
+
+BINARY="$1"
+MODE="$2"
+PATTERN="$3"
+
+echo "Inspecting BINARY: $BINARY" >&2
+if [[ ! -f "$BINARY" ]]; then
+  echo "ERROR: binary $BINARY not found" >&2
+  exit 1
+fi
+
+case "$MODE" in
+  arch)
+    echo "Verifying ELF architecture header matches '$PATTERN'..."
+    readelf -h "$BINARY" | grep "$PATTERN" >/dev/null || {
+      echo "ERROR: ELF header for $BINARY does not match expected architecture '$PATTERN'" >&2
+      readelf -h "$BINARY" >&2
+      exit 1
+    }
+    ;;
+  comment)
+    echo "Verifying ELF .comment section matches '$PATTERN'..."
+    readelf -p .comment "$BINARY" | grep "$PATTERN" >/dev/null || {
+      echo "ERROR: ELF .comment section for $BINARY does not match '$PATTERN'" >&2
+      readelf -p .comment "$BINARY" >&2
+      exit 1
+    }
+    ;;
+  symbol)
+    echo "Verifying binary symbol table contains '$PATTERN'..."
+    nm "$BINARY" | grep "$PATTERN" >/dev/null || {
+      echo "ERROR: Symbol '$PATTERN' not found in $BINARY" >&2
+      exit 1
+    }
+    ;;
+  needed)
+    echo "Verifying ELF NEEDED dynamic dependencies contain '$PATTERN'..."
+    readelf -d "$BINARY" | grep "$PATTERN" >/dev/null || {
+      echo "ERROR: Dynamic dependency '$PATTERN' not found in $BINARY" >&2
+      readelf -d "$BINARY" >&2
+      exit 1
+    }
+    ;;
+  not_needed)
+    echo "Verifying ELF NEEDED dynamic dependencies do NOT contain '$PATTERN'..."
+    if readelf -d "$BINARY" | grep "$PATTERN" >/dev/null; then
+      echo "ERROR: Unexpected dynamic dependency '$PATTERN' found in $BINARY" >&2
+      readelf -d "$BINARY" >&2
+      exit 1
+    fi
+    ;;
+  *)
+    echo "ERROR: Unknown verification mode '$MODE'" >&2
+    exit 1
+    ;;
+esac
+
+echo "SUCCESS: Verified $MODE '$PATTERN' in $BINARY."