Skip to content

fix(ci): make host-asan test jobs find and use the ASAN runtime - #8268

Merged
dileepr1 merged 1 commit into
mainfrom
users/dravindr/asan-runtime-layout
Sep 22, 2026
Merged

dileepr1 merged 1 commit into
mainfrom
users/dravindr/asan-runtime-layout

Conversation

@dileepr1

@dileepr1 dileepr1 commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

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-tests shards failed without running a single test, and with zero AddressSanitizer findings:

catch_tests/RTC: error while loading shared libraries: libclang_rt.asan-x86_64.so: cannot open shared object file
CMake Error at CatchAddTests.cmake:82: Error listing tests from executable '.../RTC': Result: 127
ctest ... returned non-zero exit status 8

ctest runs RTC --list-tests to 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-asan

return BUILD_VARIANT == "asan"

An exact match, so host-asan (and asan-debug, host-asan-debug) evaluated false and everything gated on it silently did nothing:

Caller What was skipped
test_hiptests.py LD_PRELOAD of the runtime, HSA_XNACK, extended timeout
test_rocprofiler_sdk.py clang resource dir on the loader path, preload, ASAN test exclusions
test_hipfile.py preload
test_rocblas.py, test_hipblas.py, test_hipblaslt.py HSA_XNACK
tests/test_rocm_sanity.py the #3312 rocminfo skip

The test_hiptests.py preload is the one that breaks discovery. Notably the machinery was already correct — get_asan_lib_path() there asks clang for libclang_rt.asan-<arch>.so, exactly the name RTC needs — it just never ran.

The rest of the codebase already treats these as a family: fetch_test_configurations.py uses "asan" in build_variant with a comment listing all four variants, configure_multi_arch_ci.py uses suffix in ("asan", "host-asan"), and publish_rocm_to_release_buckets.py has _is_asan_variant(). is_asan() was the odd one out.

2. configure_asan_env.py pinned one runtime filename

ASAN_RUNTIME_LIB = "libclang_rt.asan.so" is the per-target-runtime-dir name. #8077 (cd8ed0c3f) set LLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF, moving the runtime to lib/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:

Run TheRock base Result
34549006044 b85dc2119 (pre-#8077) resolved .../x86_64-unknown-linux-gnu/libclang_rt.asan.so
34613837319 24cc5c7d6 not found
35004915528 24cc5c7d6 not found

Technical Details

is_asan() now matches any ASAN-family variant via "asan" in BUILD_VARIANT, mirroring fetch_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.py

Test 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. That skipif is parametrized over three search patterns, so three sanity tests that were passing under host-asan are now skipped, taking the sanity tally from 1 failed, 4 passed, 3 skipped to 1 failed, 1 passed, 6 skipped:

test_rocm_output[rocminfo - GPU Device Type Search]   SKIPPED
test_rocm_output[rocminfo - GFX Name Search]          SKIPPED
test_rocm_output[rocminfo - AMD Vendor Name Search]   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 skipif to 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

Flags / Guardrails

None.

Adjacent Tests Considered

rocprofiler_sdk_dashboard_test.py patches is_asan directly rather than driving it through BUILD_VARIANT, so it is unaffected by the widening and needed no change.

Risk Acceptance / Waivers

None.

Technical Changes

  • is_asan() matches any ASAN-family BUILD_VARIANT instead of exactly "asan".
  • configure_asan_env.py resolves the ASAN runtime under either the per-target or the legacy arch-suffixed filename.
  • Add a unit test for the legacy name.

Submission Checklist

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>
@therock-pr-bot

therock-pr-bot Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

Comment on lines 75 to +84
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", "")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expanding this is also going to skip our test for rocminfo here:

class TestROCmSanity:
@pytest.mark.skipif(is_windows(), reason="rocminfo is not supported on Windows")
# TODO(#3312): Re-enable once rocminfo test is fixed for ASAN builds
@pytest.mark.skipif(
is_asan(), reason="rocminfo test fails with ASAN build, see TheRock#3312"
)

We may want to differentiate between host asan and device asan in test skipping.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree!
I'll get a new PR for it after merging, and update this comment as well.

Comment on lines 62 to 81
@@ -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"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have some other code across the project that is also checking for the asan runtime path, such as

def get_asan_lib_path():
arch = platform.machine()
CLANG_PATH = str(Path(THEROCK_BIN_DIR).parent / "lib" / "llvm" / "bin" / "clang++")
cmd = [f"{CLANG_PATH}", f"--print-file-name=libclang_rt.asan-{arch}.so"]
logging.info(f"++ Exec [{CLANG_PATH}]$ {shlex.join(cmd)}")
result = subprocess.run(
cmd,
check=True,
text=True,
capture_output=True,
)
return result.stdout.strip()

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.

@dileepr1
dileepr1 merged commit e49f29a into main Sep 22, 2026
183 of 189 checks passed
@dileepr1
dileepr1 deleted the users/dravindr/asan-runtime-layout branch September 22, 2026 16:05
@github-project-automation github-project-automation Bot moved this from TODO to Done in TheRock Triage Sep 22, 2026
dileepr1 added a commit that referenced this pull request Sep 22, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants