[flang-commits] [flang] [llvm] [flang-rt][cuda] Skip scope-exit cleanup when the context has a sticky error (PR #213184)

Zhen Wang via flang-commits flang-commits at lists.llvm.org
Thu Jul 30 17:56:52 PDT 2026


https://github.com/wangzpgi created https://github.com/llvm/llvm-project/pull/213184

A sticky CUDA error (e.g. an illegal memory access in a kernel) leaves the primary context active but unusable, so CUFDeviceIsActive() reports it as fine and the compiler-generated scope-exit frees abort a program that ran to completion: 'cudaFree(p)' failed with 'cudaErrorIllegalAddress'.

Detect this by freeing a null pointer, a no-op that still reports the sticky error. It runs only once the primary context is known active, so it cannot lazily create one.

>From 05619745e20bb0828804cd624d2dea119673fca1 Mon Sep 17 00:00:00 2001
From: Zhen Wang <zhenw at nvidia.com>
Date: Thu, 30 Jul 2026 16:28:57 -0700
Subject: [PATCH] Treat a sticky-error context as torn down in
 CUFDeviceIsActive

---
 flang-rt/lib/cuda/allocator.cpp         | 7 +++++++
 flang/test/Lower/CUDA/cuda-return01.cuf | 6 ++++++
 2 files changed, 13 insertions(+)

diff --git a/flang-rt/lib/cuda/allocator.cpp b/flang-rt/lib/cuda/allocator.cpp
index 4161caa7cb022..d8287d6f696e3 100644
--- a/flang-rt/lib/cuda/allocator.cpp
+++ b/flang-rt/lib/cuda/allocator.cpp
@@ -59,6 +59,13 @@ static bool deviceContextTornDown() {
       int active{0};
       if (getState(device, &flags, &active) == CUDA_SUCCESS) {
         tornDown = active == 0;
+        // A sticky error (e.g. an illegal kernel memory access) leaves the
+        // primary context active but unusable: later calls all fail, so
+        // scope-exit frees would abort an otherwise successful program. A
+        // null free is a no-op that surfaces this without creating a context.
+        if (!tornDown && cudaFree(nullptr) != cudaSuccess) {
+          tornDown = true;
+        }
       }
     }
   } else {
diff --git a/flang/test/Lower/CUDA/cuda-return01.cuf b/flang/test/Lower/CUDA/cuda-return01.cuf
index 6e5d02c3b3962..9ea5ce1538081 100644
--- a/flang/test/Lower/CUDA/cuda-return01.cuf
+++ b/flang/test/Lower/CUDA/cuda-return01.cuf
@@ -31,13 +31,19 @@ end
 
 program main
   integer, allocatable, device :: a(:)
+  integer, device, pointer :: p(:)
   return
 end
 
+! The descriptor of a device pointer lives in managed memory and is freed at
+! scope exit, under the same device-active guard as the other cleanup.
+
 ! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "MAIN"}
 ! CHECK: cuf.alloc !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "a", data_attr = #cuf.cuda<device>, uniq_name = "_QFEa"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK: %[[PTR:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFEp"}
 ! CHECK: %[[ACTIVE:.*]] = fir.call @_FortranACUFDeviceIsActive() {{.*}} : () -> i1
 ! CHECK-NEXT: fir.if %[[ACTIVE]] {
+! CHECK-NEXT: cuf.free %[[PTR]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>{{.*}}
 ! CHECK: cuf.deallocate
 ! CHECK: cuf.free{{.*}}
 ! CHECK-NEXT: }



More information about the flang-commits mailing list