This directory contains all test executables for verifying compiler hardening features.
A simple test that always passes and logs compiler and platform information. Useful for verifying the build environment.
Validates that libc++ hardening correctly aborts when a violation is detected on macOS. This test intentionally triggers an out-of-bounds access to verify that hardening checks are working.
The test intentionally triggers a hardening assertion by performing an out-of-bounds access on a std::span:
std::span<udt> sp(arr);
volatile udt out_of_bounds = sp[10]; // Index 10 is out of bounds (array has 5 elements)With hardening enabled:
- Expected behavior on macOS: The program aborts when the hardening check detects the violation (test passes via
WILL_FAIL TRUE) - Other platforms: The test runs but may not have hardening checks, so it reports
HARDENING_TEST_SKIPPED
# Configure for Apple Clang with Debug mode
cmake --preset=apple-clang-arm64-debug # or apple-clang-x64-debug
# Build
cmake --build --preset=apple-clang-arm64-debug
# Run all tests via CTest
ctest --preset=apple-clang-arm64-debug --output-on-failure
# Run a specific test directly
./build/apple-clang-arm64-debug/test-report
# Note: test-hardening-assertions will abort when run directly (expected behavior)Tests compile and run on all platforms. The hardening test may not trigger aborts on platforms without libc++ hardening support.
The following tests are configured:
report: Always passes, logs compiler and platform information (all platforms)hardening_assertions: Runs on all platforms- On macOS: Wrapped in shell command that detects signal termination. Test passes when exit code > 128 (indicating process was killed by signal: SIGABRT=134, SIGILL=132).
- On other platforms: Runs normally, should pass if hardening not available
The macOS test uses: bash -c "$<TARGET_FILE:test-hardening-assertions>; exit $(( $? > 128 ? 0 : 1 ))" which converts signal termination (exit code > 128) to success (exit 0).
All tests are compiled with compiler-specific hardening flags using the apply_hardening_flags() function in CMakeLists.txt.
On macOS, tests use:
Debug mode:
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG: Enables debug mode hardening (all checks, aborts on violations)
Release mode:
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST: Enables fast mode hardening (security-critical checks, aborts on violations)
Hello, World!
Compiler Hardening Test Application
Compiler: Apple Clang 15.0
Architecture: ARM64
When run via CTest on non-macOS platforms:
Test project /path/to/build
Start 1: report
1/2 Test #1: report ........................... Passed 0.01 sec
Start 2: hardening_assertions
2/2 Test #2: hardening_assertions ............. Passed 0.01 sec
100% tests passed, 0 tests failed out of 2
When run via CTest on macOS (signal termination is expected):
Test project /path/to/build
Start 1: report
1/2 Test #1: report ........................... Passed 0.00 sec
Start 2: hardening_assertions
2/2 Test #2: hardening_assertions ............. Passed 0.00 sec
100% tests passed, 0 tests failed out of 2
The shell wrapper checks the exit code: if > 128 (signal termination), it returns 0 (success); otherwise returns 1 (failure).
When run directly (bypassing shell wrapper):
./build/apple-clang-arm64-debug/test-hardening-assertionsOn macOS:
Testing libc++ hardening assertion behavior
Valid access: sp[2]._a = 3
Attempting out-of-bounds access...
Triggering hardening violation (expecting abort)...
libc++: hardening violation: out of bounds access detected
Illegal instruction: 4 (or Abort trap: 6)
On other platforms:
Testing libc++ hardening assertion behavior
Valid access: sp[2]._a = 3
Attempting out-of-bounds access...
Test running on non-macOS platform (no hardening checks)
HARDENING_TEST_SKIPPED
Key points:
- On macOS, the program must be killed by signal (exit code > 128) for the test to pass
- Shell wrapper converts signal termination to test success (exit 0)
- On non-macOS platforms, the test passes normally (no hardening)
If a test fails:
- On macOS: If
hardening_assertionsfails, it means the program did NOT crash (hardening is not working) - Examine the compiler flags:
cmake --build --preset=apple-clang-arm64-debug --verbose - Check if hardening is enabled by looking for
-D_LIBCPP_HARDENING_MODEin the compile commands - Check CTest output:
ctest --preset=apple-clang-arm64-debug -V(verbose mode) - Run the test directly to see raw behavior:
./build/apple-clang-arm64-debug/test-hardening-assertions
The macOS test uses a shell wrapper to detect and validate signal termination:
bash -c "$<TARGET_FILE:test-hardening-assertions>; exit $(( $? > 128 ? 0 : 1 ))"How it works:
- Runs the test executable
- Captures exit code in
$? - When process is killed by signal: exit code =
128 + signal_number- SIGABRT (6) → exit code 134
- SIGILL (4) → exit code 132
- Uses arithmetic: if exit code > 128, return 0 (success), else return 1 (failure)
- CTest sees exit 0 → test passes ✓
Why this works:
- If hardening is working: Process killed by signal → exit code 134 or 132 → wrapper returns 0 → ✓ PASS
- If hardening is NOT working: Process exits normally with 0 or 1 → exit code ≤ 128 → wrapper returns 1 → ✗ FAIL
Success criteria on macOS: The program must be killed by a signal (SIGABRT or SIGILL) when the hardening violation occurs.