Files
TheRock/rocm-systems/projects/rocprofiler-compute/cmake/sanitizers.cmake
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

217 lines
8.2 KiB
CMake

## Copyright (c) Advanced Micro Devices, Inc.
## SPDX-License-Identifier: MIT
include_guard(GLOBAL)
# Fold THEROCK_SANITIZER and legacy ENABLE_ADDRESS_SANITIZER into the canonical
# ENABLE_SANITIZER, precedence THEROCK_SANITIZER > ENABLE_SANITIZER >
# ENABLE_ADDRESS_SANITIZER, so every downstream site reads one variable.
function(resolve_sanitizer)
set(therock_sanitizer_valid
""
"OFF"
"ASAN"
"HOST_ASAN"
"TSAN"
)
# Empty string is omitted by variable expansion, so add it explicitly.
set(sanitizer_valid "" ${therock_sanitizer_valid} "UBSAN")
# Human-readable forms for the error messages, derived from the lists so they
# cannot drift. Drop the empty-string placeholder.
set(therock_sanitizer_display ${therock_sanitizer_valid})
list(REMOVE_ITEM therock_sanitizer_display "")
list(JOIN therock_sanitizer_display ", " therock_sanitizer_display)
set(sanitizer_display ${sanitizer_valid})
list(REMOVE_ITEM sanitizer_display "")
list(JOIN sanitizer_display ", " sanitizer_display)
if(
DEFINED THEROCK_SANITIZER
AND NOT THEROCK_SANITIZER IN_LIST therock_sanitizer_valid
)
message(
FATAL_ERROR
"THEROCK_SANITIZER='${THEROCK_SANITIZER}' is not one of: ${therock_sanitizer_display}"
)
endif()
set(sanitizer_provenance "-DENABLE_SANITIZER")
if(DEFINED THEROCK_SANITIZER AND NOT THEROCK_SANITIZER STREQUAL "")
set(ENABLE_SANITIZER
"${THEROCK_SANITIZER}"
CACHE STRING
"Sanitizer for the native tool library (driven by THEROCK_SANITIZER)"
FORCE
)
set(sanitizer_provenance "THEROCK_SANITIZER")
elseif(
(ENABLE_SANITIZER STREQUAL "" OR ENABLE_SANITIZER STREQUAL "OFF")
AND ENABLE_ADDRESS_SANITIZER
)
# Promote ENABLE_ADDRESS_SANITIZER to ASAN so downstream only reads ENABLE_SANITIZER.
set(ENABLE_SANITIZER
"ASAN"
CACHE STRING
"Sanitizer for the native tool library (driven by ENABLE_ADDRESS_SANITIZER)"
FORCE
)
set(sanitizer_provenance "ENABLE_ADDRESS_SANITIZER")
endif()
# Normalize OFF -> "" so downstream code only tests for emptiness.
if(ENABLE_SANITIZER STREQUAL "OFF")
set(ENABLE_SANITIZER
""
CACHE STRING
"Sanitizer for the native tool library: OFF, ASAN, HOST_ASAN, TSAN, or UBSAN"
FORCE
)
endif()
if(NOT ENABLE_SANITIZER IN_LIST sanitizer_valid)
message(
FATAL_ERROR
"ENABLE_SANITIZER='${ENABLE_SANITIZER}' is not one of: ${sanitizer_display}"
)
endif()
# Nuitka onefile is incompatible with sanitizers (it execs a stripped binary
# from a temp dir; the sanitizer runtime cannot be located).
if(ENABLE_SANITIZER AND STANDALONEBINARY)
message(
FATAL_ERROR
"ENABLE_SANITIZER=${ENABLE_SANITIZER} cannot be combined with STANDALONEBINARY=ON"
)
endif()
if(ENABLE_SANITIZER)
message(STATUS "Sanitizer: ${ENABLE_SANITIZER} (from ${sanitizer_provenance})")
else()
message(STATUS "Sanitizer: OFF")
endif()
set(ENABLE_SANITIZER "${ENABLE_SANITIZER}" PARENT_SCOPE)
endfunction()
# Apply -fsanitize=... compile flags and link options to the current scope.
# Compile-flag injection is skipped when TheRock already populated -fsanitize= via
# CMAKE_CXX_FLAGS_INIT (avoid double-instrumentation); link options are emitted
# unconditionally and are idempotent, so duplication is benign.
function(enable_sanitizer)
if(NOT ENABLE_SANITIZER)
return()
endif()
if(ENABLE_SANITIZER STREQUAL "ASAN" OR ENABLE_SANITIZER STREQUAL "HOST_ASAN")
set(_flag "address")
elseif(ENABLE_SANITIZER STREQUAL "TSAN")
set(_flag "thread")
elseif(ENABLE_SANITIZER STREQUAL "UBSAN")
set(_flag "undefined")
set(_is_ubsan_mode ON)
endif()
if(CMAKE_CXX_FLAGS_INIT MATCHES "-fsanitize=")
message(
STATUS
"enable_sanitizer(): -fsanitize= already in CMAKE_CXX_FLAGS_INIT; skipping local compile-flag injection"
)
else()
set(_extra "-fsanitize=${_flag} -fno-omit-frame-pointer -g")
if(_is_ubsan_mode)
string(APPEND _extra " -fno-sanitize-recover=all -fno-sanitize=vptr")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_extra}" PARENT_SCOPE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_extra}" PARENT_SCOPE)
endif()
# clang defaults to static sanitizer linkage; gcc defaults to shared.
# Force shared on clang only.
add_link_options(
$<$<LINK_LANGUAGE:C,CXX>:-fsanitize=${_flag}>
$<$<AND:$<LINK_LANGUAGE:C,CXX>,$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>>:-shared-libsan>
)
if(_is_ubsan_mode)
add_link_options(
$<$<LINK_LANGUAGE:C,CXX>:-fno-sanitize-recover=all>
$<$<LINK_LANGUAGE:C,CXX>:-fno-sanitize=vptr>
)
endif()
endfunction()
# Rewrite GPU_TARGETS for full ASAN and TSAN modes (gfx942/gfx950 -> :xnack+).
# No-op for host-only modes or when TheRock has already rewritten the targets upstream.
function(enable_sanitizer_gpu_target_munging)
if(NOT (ENABLE_SANITIZER STREQUAL "ASAN" OR ENABLE_SANITIZER STREQUAL "TSAN"))
return()
endif()
if(NOT DEFINED GPU_TARGETS)
message(
WARNING
"${ENABLE_SANITIZER}: GPU_TARGETS is not set; skipping the gfx942/gfx950 -> :xnack+ rewrite. Pass -DGPU_TARGETS=... for device-side sanitizer instrumentation."
)
return()
endif()
# The gfx942/gfx950 arch list mirrors TheRock's regex, tracked upstream as
# TheRock TODO #3444 (ASAN variants may need xnack-suffix expansion). Keep it in
# sync with upstream rather than widening it independently.
list(TRANSFORM GPU_TARGETS REPLACE "^(gfx942|gfx950)$" "\\1:xnack+")
set(GPU_TARGETS "${GPU_TARGETS}" PARENT_SCOPE)
set(AMDGPU_TARGETS "${GPU_TARGETS}" PARENT_SCOPE)
message(STATUS "${ENABLE_SANITIZER}: GPU_TARGETS rewritten -> ${GPU_TARGETS}")
endfunction()
# Build the per-mode sanitizer runtime ENV for a ctest entry.
#
# suppress_leaks=ON keeps CPython arena/module leaks from failing the pytest
# entries when they run under the TheRock-driven sanitizer flow
# (THEROCK_SANITIZER + enable_sanitizer_python_launcher). The standalone
# sanitizer CI does not run those entries.
# suppress_leaks=OFF keeps leak detection enabled for native gtests, which is
# what the standalone sanitizer CI runs.
function(sanitizer_runtime_env out_var suppress_leaks)
set(_env "")
if(ENABLE_SANITIZER STREQUAL "ASAN" OR ENABLE_SANITIZER STREQUAL "HOST_ASAN")
if(suppress_leaks)
list(APPEND _env "ASAN_OPTIONS=detect_leaks=0")
endif()
elseif(ENABLE_SANITIZER STREQUAL "TSAN")
list(APPEND _env "TSAN_OPTIONS=second_deadlock_stack=1")
elseif(ENABLE_SANITIZER STREQUAL "UBSAN")
list(APPEND _env "UBSAN_OPTIONS=print_stacktrace=1")
endif()
set(${out_var} "${_env}" PARENT_SCOPE)
endfunction()
# Wrap the ctest python command with THEROCK_SANITIZER_LAUNCHER plus env that
# quiets known false positives.
function(enable_sanitizer_python_launcher out_var)
set(_launcher ${THEROCK_SANITIZER_LAUNCHER} ${${out_var}})
sanitizer_runtime_env(_sanitizer_env ON)
if(_sanitizer_env)
list(PREPEND _launcher "${CMAKE_COMMAND}" -E env ${_sanitizer_env})
endif()
set(${out_var} "${_launcher}" PARENT_SCOPE)
endfunction()
set(ENABLE_SANITIZER
"OFF"
CACHE STRING
"Sanitizer for the native tool library: OFF, ASAN, HOST_ASAN, TSAN, or UBSAN"
)
set_property(
CACHE ENABLE_SANITIZER
PROPERTY STRINGS OFF ASAN HOST_ASAN TSAN UBSAN
)
# Drive all three side effects at include time: resolve the selection, rewrite GPU
# targets, inject compile/link flags. CMAKE_CXX_FLAGS propagates into src/lib via
# subdir inheritance, so subdirs need no sanitizer awareness. The runtime JIT build
# of src/lib does not include this module, so it stays sanitizer-free. The python
# launcher is wired separately once PYTHON_TEST_COMMAND is defined.
resolve_sanitizer()
enable_sanitizer_gpu_target_munging()
enable_sanitizer()