Skip to content

Commit 3cbda99

Browse files
rocrtst: Complete deferred ASAN frees before checking free results
Drain the ASAN quarantine with __sanitizer_purge_allocator(), so the deferred release completes before each check (ROCRTST_ASAN-guarded). The recursive and double-free notifier callbacks run while the quarantine is already being drained, and the drain cannot be invoked again from inside itself, so their inner repeated callback checks are skipped under ASAN. The outer notifier behavior is still validated. Signed-off-by: Apurv Mishra <Apurv.Mishra@amd.com>
1 parent 4badac6 commit 3cbda99

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

projects/rocr-runtime/rocrtst/suites/functional/deallocation_notifier.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ struct callback_status {
7777
static callback_status notifiers[2];
7878
static hsa_amd_memory_pool_t pool;
7979

80+
#ifdef ROCRTST_ASAN
81+
// ASAN defers the real free (and thus the notifier) via its quarantine; drain
82+
// it so callbacks have run before we check them.
83+
extern "C" void __sanitizer_purge_allocator(void);
84+
static inline void DrainAsanQuarantine() { __sanitizer_purge_allocator(); }
85+
#else
86+
static inline void DrainAsanQuarantine() {}
87+
#endif
88+
8089
#define REGISTER(ptr, callback, i) \
8190
do { \
8291
notifiers[i].callback_status = 0; \
@@ -94,8 +103,12 @@ static void call(void* ptr, void* user) {
94103
static void doublefree(void* ptr, void* user) {
95104
call(ptr, user);
96105

106+
#ifndef ROCRTST_ASAN
107+
// Skip under ASAN: this runs during a quarantine drain, where a second free
108+
// trips the sanitizer's own double-free report before ROCr can return.
97109
hsa_status_t status = hsa_amd_memory_pool_free(ptr);
98110
ASSERT_EQ(HSA_STATUS_ERROR_INVALID_ALLOCATION, status) << "Double free did not return an error.";
111+
#endif
99112
}
100113

101114
static void recursive(void* ptr, void* user) {
@@ -106,7 +119,11 @@ static void recursive(void* ptr, void* user) {
106119
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory allocation failure.";
107120
REGISTER(ptr, call, 1);
108121
hsa_amd_memory_pool_free(ptr);
122+
#ifndef ROCRTST_ASAN
123+
// Skip under ASAN: the inner free can't be drained re-entrantly from within
124+
// a drain, so its notifier fires later (at the next drain/teardown).
109125
ASSERT_EQ(1, notifiers[1].callback_status) << "Callback not executed.";
126+
#endif
110127
}
111128

112129
DeallocationNotifierTest::DeallocationNotifierTest() : TestBase() {
@@ -187,6 +204,7 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
187204
REGISTER(ptr, call, 0);
188205
status = hsa_amd_memory_pool_free(ptr);
189206
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
207+
DrainAsanQuarantine();
190208
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
191209

192210
// Re-allocate, free. No callback should be invoked.
@@ -203,6 +221,7 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
203221
REGISTER((char*)ptr + 1024, call, 0);
204222
status = hsa_amd_memory_pool_free(ptr);
205223
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
224+
DrainAsanQuarantine();
206225
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
207226

208227
// Allocate, Register, Deregister, Free. No callback should be invoked.
@@ -222,6 +241,7 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
222241
REGISTER((char*)ptr + 1024, call, 1);
223242
status = hsa_amd_memory_pool_free(ptr);
224243
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
244+
DrainAsanQuarantine();
225245
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
226246
ASSERT_EQ(1, notifiers[1].callback_status) << "Callback not executed.";
227247

@@ -242,6 +262,7 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
242262
REGISTER(ptr, call, 0);
243263
status = hsa_amd_memory_pool_free(ptr);
244264
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
265+
DrainAsanQuarantine();
245266
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
246267

247268
// Allocate multiple fragments, register, free. Free order should be respected by callbacks.
@@ -252,10 +273,12 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
252273
REGISTER(ptr0, call, 1);
253274
status = hsa_amd_memory_pool_free(ptr0);
254275
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
276+
DrainAsanQuarantine();
255277
ASSERT_EQ(1, notifiers[1].callback_status) << "Callback not executed.";
256278
ASSERT_EQ(0, notifiers[0].callback_status) << "Callback executed improperly.";
257279
status = hsa_amd_memory_pool_free(ptr);
258280
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
281+
DrainAsanQuarantine();
259282
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
260283

261284
// Allocate, register, free, with double free in callback. Callbacks should not be able to free
@@ -265,6 +288,7 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
265288
REGISTER(ptr, doublefree, 0);
266289
status = hsa_amd_memory_pool_free(ptr);
267290
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
291+
DrainAsanQuarantine();
268292
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
269293

270294
// Allocate, register, free, with allocate, register, free in callback. Callbacks should nest and
@@ -274,5 +298,6 @@ void DeallocationNotifierTest::TestDeallocationNotifier(void) {
274298
REGISTER(ptr, recursive, 0);
275299
status = hsa_amd_memory_pool_free(ptr);
276300
ASSERT_EQ(HSA_STATUS_SUCCESS, status) << "Memory free failure.";
301+
DrainAsanQuarantine();
277302
ASSERT_EQ(1, notifiers[0].callback_status) << "Callback not executed.";
278303
}

projects/rocr-runtime/rocrtst/suites/functional/memory_basic.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@
5757
#include "gtest/gtest.h"
5858
#include "hsa/hsa.h"
5959

60+
#ifdef ROCRTST_ASAN
61+
// ASAN defers the real free via its quarantine; drain it so freed VRAM is
62+
// returned before we query available memory.
63+
extern "C" void __sanitizer_purge_allocator(void);
64+
static inline void DrainAsanQuarantine() { __sanitizer_purge_allocator(); }
65+
#else
66+
static inline void DrainAsanQuarantine() {}
67+
#endif
68+
6069
static const uint32_t kNumBufferElements = 256;
6170

6271
#define RET_IF_HSA_ERR(err) { \
@@ -531,6 +540,8 @@ void MemoryTest::MemAvailableTest(hsa_agent_t ag, hsa_amd_memory_pool_t pool) {
531540
err = hsa_amd_memory_pool_free(memPtr2);
532541
ASSERT_EQ(err, HSA_STATUS_SUCCESS);
533542

543+
DrainAsanQuarantine();
544+
534545
err = hsa_agent_get_info(ag, (hsa_agent_info_t)HSA_AMD_AGENT_INFO_MEMORY_AVAIL,
535546
&ag_avail_memory_after);
536547
ASSERT_EQ(err, HSA_STATUS_SUCCESS);

0 commit comments

Comments
 (0)