Repository navigation
fix(ci): make host-asan test jobs find and use the ASAN runtime - #8268
Conversation
Two consumers of the ASAN runtime broke, both surfaced by the rocm-systems host-asan presubmit, where all four hip-tests shards failed without running a single test. 1. is_asan() matched BUILD_VARIANT exactly against "asan", so it was false for "host-asan". Everything gated on it silently did nothing: the LD_PRELOAD and HSA_XNACK in test_hiptests.py, the loader path and test exclusions in test_rocprofiler_sdk.py, the preload in test_hipfile.py, HSA_XNACK in the blas scripts. Without the preload, Catch2 discovery cannot load the instrumented RTC binary, so ctest exits 8 and the shards report failure with zero tests run. The rest of the codebase already treats the variants as a family (fetch_test_configurations.py, configure_multi_arch_ci.py, publish_rocm_to_release_buckets.py); this brings is_asan() in line. 2. configure_asan_env.py pinned the runtime filename to libclang_rt.asan.so. #8077 set LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF, which renames it to libclang_rt.asan-<arch>.so under lib/linux, so resolution started failing and every ASAN job logged "ASAN runtime not found". Try both names, since TheRock has flipped between the layouts. Note that widening is_asan() also activates the TheRock#3312 rocminfo skip for host-asan, where that test currently passes. Skipping it loses a little coverage, but leaving the variants inconsistent hides real failures. Co-authored-by: Cursor <cursoragent@cursor.com>
✅ All Policy Checks Passed
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🎉 All checks passed! This PR is ready for review. |
| def is_asan(): | ||
| """Determines if this is an ASAN build using BUILD_VARIANT env var.""" | ||
| BUILD_VARIANT = os.getenv("BUILD_VARIANT", "") | ||
| return BUILD_VARIANT == "asan" | ||
| """Determines if this is an ASAN-family build using BUILD_VARIANT env var. | ||
|
|
||
| Matches "asan", "host-asan" and their "-debug" forms, like the check in | ||
| fetch_test_configurations.py. An exact match on "asan" leaves host-asan test | ||
| jobs without the ASAN handling their callers apply -- most visibly the | ||
| LD_PRELOAD in test_hiptests.py, without which Catch2 cannot load the | ||
| instrumented binaries to enumerate tests. | ||
| """ | ||
| return "asan" in os.getenv("BUILD_VARIANT", "") |
There was a problem hiding this comment.
Expanding this is also going to skip our test for rocminfo here:
TheRock/tests/test_rocm_sanity.py
Lines 58 to 63 in 8438943
We may want to differentiate between host asan and device asan in test skipping.
There was a problem hiding this comment.
Agree!
I'll get a new PR for it after merging, and update this comment as well.
| @@ -72,20 +80,23 @@ def _resolve_asan_runtime( | |||
| if not os.access(clang, os.X_OK): | |||
| return None, f"clang not found at {clang}, ASAN runtime path not resolved" | |||
There was a problem hiding this comment.
We have some other code across the project that is also checking for the asan runtime path, such as
TheRock/build_tools/github_actions/test_executable_scripts/test_hiptests.py
Lines 109 to 120 in 8438943
I also want our tests to match our documentation in more places, e.g. https://github.com/ROCm/TheRock/blob/main/docs/development/sanitizers.md#step-2-locate-the-asan-runtime-directory
I think this is fine for now though.
get_asan_lib_path() hardcoded libclang_rt.asan-<arch>.so, the mirror of the bug #8268 fixed in configure_asan_env.py: it breaks when the toolchain uses per-target runtime directories, and it fails silently because clang exits zero and echoes the requested name back. Route it through the shared resolver instead, which tries both spellings and raises when neither exists. Co-authored-by: Cursor <cursoragent@cursor.com>
Motivation
In Short:
#8268 fixes two independent bugs that together made every host-ASan hip-tests shard fail without running a single test.
First, is_asan() matched BUILD_VARIANT exactly against "asan", so it was false for host-asan and everything gated on it silently did nothing
Second, configure_asan_env.py pinned the runtime filename to libclang_rt.asan.so, which #8077 renamed to libclang_rt.asan-.so, so the ASan runtime hadn't resolved at all since that landed.
Details
GitHub issue: #7202
Found while looking at the first host-asan presubmit run that got as far as the component test matrix (ROCm/rocm-systems#10088, run 35004915528). All four
hip-testsshards failed without running a single test, and with zero AddressSanitizer findings:ctest runs
RTC --list-teststo enumerate Catch2 tests; it cannot load the instrumented binary, CMake aborts the listing, and the shard reports failure. Two separate defects combine to produce this.1.
is_asan()excluded host-asanAn exact match, so
host-asan(andasan-debug,host-asan-debug) evaluated false and everything gated on it silently did nothing:test_hiptests.pyLD_PRELOADof the runtime,HSA_XNACK, extended timeouttest_rocprofiler_sdk.pytest_hipfile.pytest_rocblas.py,test_hipblas.py,test_hipblaslt.pyHSA_XNACKtests/test_rocm_sanity.pyThe
test_hiptests.pypreload is the one that breaks discovery. Notably the machinery was already correct —get_asan_lib_path()there asks clang forlibclang_rt.asan-<arch>.so, exactly the nameRTCneeds — it just never ran.The rest of the codebase already treats these as a family:
fetch_test_configurations.pyuses"asan" in build_variantwith a comment listing all four variants,configure_multi_arch_ci.pyusessuffix in ("asan", "host-asan"), andpublish_rocm_to_release_buckets.pyhas_is_asan_variant().is_asan()was the odd one out.2.
configure_asan_env.pypinned one runtime filenameASAN_RUNTIME_LIB = "libclang_rt.asan.so"is the per-target-runtime-dir name. #8077 (cd8ed0c3f) setLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF, moving the runtime tolib/linux/libclang_rt.asan-<arch>.so. Resolution has failed ever since, and every ASAN test job has been logging##[warning]ASAN runtime not found. The regression is visible across runs:b85dc2119(pre-#8077).../x86_64-unknown-linux-gnu/libclang_rt.asan.so24cc5c7d624cc5c7d6Technical Details
is_asan()now matches any ASAN-family variant via"asan" in BUILD_VARIANT, mirroringfetch_test_configurations.py._resolve_asan_runtime()tries both filenames in turn, per-target first then the legacy arch-suffixed one, relying on the fact that clang echoes the requested name back unchanged when it cannot locate the file. The warning now names both candidates. TheRock has flipped between these layouts, so pinning either one is fragile.Test Plan
python -m pytest build_tools/ tests/ -q --continue-on-collection-errors(against baseline)pre-commit run --files build_tools/github_actions/amdgpu_family_matrix.py build_tools/github_actions/configure_asan_env.py build_tools/github_actions/tests/configure_asan_env_test.pyTest Result
2432 passed / 16 failed / 6 collection errors, against a baseline of 2431 passed / 16 failed / 6 collection errors on
origin/main. The failures and collection errors are identical on both sides and are pre-existing local dependency gaps (zlib_ng,pkginfo,_rocm_sdk_core_DEFAULT); the delta is the one test added here. Targeted pre-commit passed.Risk Assessment
Risk 3. Widening
is_asan()activates ASAN handling for host-asan across several test scripts that have never had it, which is the intent but does change their behavior. The specific known side effect is that the TheRock#3312 rocminfo skip now applies to host-asan. Thatskipifis parametrized over three search patterns, so three sanity tests that were passing under host-asan are now skipped, taking the sanity tally from1 failed, 4 passed, 3 skippedto1 failed, 1 passed, 6 skipped:That coverage loss is accepted here in exchange for the variants behaving consistently. Worth a follow-up: #3312 was filed against full ASAN, and these tests demonstrably pass under host-asan, so narrowing that
skipifto the full-ASAN variant may be the better long-term answer. The runtime-name change is additive: it only adds a second candidate after the existing one fails.Related
Device / Architecture Coverage
Validated on gfx942 via the rocm-systems host-asan presubmit. No device code changes.
Testing Summary
Added
test_resolves_the_legacy_arch_suffixed_runtime, which stubs a clang that resolves only the arch-suffixed name and echoes the request back otherwise, matching real clang behavior. Existing coverage for the per-target name, missing clang, missing runtime, missing symbolizer and the GITHUB_ENV format is unchanged.Testing Checklist
hsa_amd_memory_pool_freebad-free. The runtime now resolves to.../lib/clang/24/lib/linux/libclang_rt.asan-x86_64.so, confirming the revert(compiler): LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON #8077 layout.Flags / Guardrails
None.
Adjacent Tests Considered
rocprofiler_sdk_dashboard_test.pypatchesis_asandirectly rather than driving it throughBUILD_VARIANT, so it is unaffected by the widening and needed no change.Risk Acceptance / Waivers
None.
Technical Changes
is_asan()matches any ASAN-familyBUILD_VARIANTinstead of exactly"asan".configure_asan_env.pyresolves the ASAN runtime under either the per-target or the legacy arch-suffixed filename.Submission Checklist