Skip to content

Commit 9e42723

Browse files
committed
Don't let C++ exception percolate out of library
1 parent d5551e4 commit 9e42723

2 files changed

Lines changed: 60 additions & 18 deletions

File tree

src/cupti.cpp

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -310,15 +310,26 @@ class CuptiProfiler : public proton::Singleton<CuptiProfiler> {
310310
}
311311
}
312312

313-
// Flush any remaining activity records
314-
proton::cupti::activityFlushAll<true>(CUPTI_ACTIVITY_FLAG_FLUSH_FORCED);
313+
// Cleanup runs from atexit and may also reach us via a libcupti callback
314+
// whose caller wasn't built with C++ EH; throwing from here aborts the
315+
// process. Use <false> + log on the cleanup-path calls.
316+
if (auto r = proton::cupti::activityFlushAll<false>(
317+
CUPTI_ACTIVITY_FLAG_FLUSH_FORCED);
318+
r != CUPTI_SUCCESS) {
319+
DEBUG_PRINTF("[PARCAGPU] activityFlushAll failed: %d\n", r);
320+
}
315321

316-
// Disable activity recording
317-
proton::cupti::activityDisable<true>(CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL);
322+
if (auto r = proton::cupti::activityDisable<false>(
323+
CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL);
324+
r != CUPTI_SUCCESS) {
325+
DEBUG_PRINTF("[PARCAGPU] activityDisable failed: %d\n", r);
326+
}
318327

319-
// Unsubscribe
320328
if (subscriber) {
321-
proton::cupti::unsubscribe<true>(subscriber);
329+
if (auto r = proton::cupti::unsubscribe<false>(subscriber);
330+
r != CUPTI_SUCCESS) {
331+
DEBUG_PRINTF("[PARCAGPU] unsubscribe failed: %d\n", r);
332+
}
322333
subscriber = nullptr;
323334
}
324335

@@ -477,6 +488,10 @@ class CuptiProfiler : public proton::Singleton<CuptiProfiler> {
477488

478489
static void callbackHandler(void *userdata, CUpti_CallbackDomain domain,
479490
CUpti_CallbackId cbid, const void *cbdata_void) {
491+
// libcupti invokes us from contexts whose callers weren't built with
492+
// C++ EH support, so any uncaught throw aborts the process. Treat the
493+
// whole body as untrusted and swallow exceptions at the boundary.
494+
try {
480495
auto &profiler = CuptiProfiler::instance();
481496

482497
if (domain == CUPTI_CB_DOMAIN_RESOURCE) {
@@ -677,26 +692,48 @@ class CuptiProfiler : public proton::Singleton<CuptiProfiler> {
677692
if (profiler.outstandingEvents > 3000) {
678693
DEBUG_PRINTF("[PARCAGPU] Flushing: outstandingEvents=%zu\n",
679694
profiler.outstandingEvents);
680-
proton::cupti::activityFlushAll<true>(0);
695+
if (auto r = proton::cupti::activityFlushAll<false>(0);
696+
r != CUPTI_SUCCESS) {
697+
DEBUG_PRINTF("[PARCAGPU] activityFlushAll failed: %d\n", r);
698+
}
681699
profiler.outstandingEvents = 0;
682700
}
683701
}
702+
} catch (const std::exception &e) {
703+
fprintf(stderr, "[PARCAGPU] callbackHandler caught: %s\n", e.what());
704+
} catch (...) {
705+
fprintf(stderr, "[PARCAGPU] callbackHandler caught unknown exception\n");
706+
}
684707
}
685708
};
686709

687710
} // namespace parcagpu
688711

689-
// CUPTI initialization function required for CUDA_INJECTION64_PATH
712+
// CUPTI initialization function required for CUDA_INJECTION64_PATH.
713+
// Called from the CUDA driver, which wasn't built with C++ EH; a throw out
714+
// of here would abort the host process. Catch everything at the boundary.
690715
extern "C" int InitializeInjection(void) {
691716
DEBUG_PRINTF("[PARCAGPU] InitializeInjection called\n");
692-
693-
auto &profiler = parcagpu::CuptiProfiler::instance();
694-
if (!profiler.initialize()) {
695-
return 0; // Return 0 on failure, but don't break injection
717+
try {
718+
auto &profiler = parcagpu::CuptiProfiler::instance();
719+
if (!profiler.initialize()) {
720+
return 0; // Return 0 on failure, but don't break injection
721+
}
722+
atexit([]() {
723+
try {
724+
parcagpu::CuptiProfiler::instance().cleanup();
725+
} catch (const std::exception &e) {
726+
fprintf(stderr, "[PARCAGPU] cleanup caught: %s\n", e.what());
727+
} catch (...) {
728+
fprintf(stderr, "[PARCAGPU] cleanup caught unknown exception\n");
729+
}
730+
});
731+
return 1;
732+
} catch (const std::exception &e) {
733+
fprintf(stderr, "[PARCAGPU] InitializeInjection caught: %s\n", e.what());
734+
return 0;
735+
} catch (...) {
736+
fprintf(stderr, "[PARCAGPU] InitializeInjection caught unknown exception\n");
737+
return 0;
696738
}
697-
698-
// Register cleanup at exit
699-
atexit([]() { parcagpu::CuptiProfiler::instance().cleanup(); });
700-
701-
return 1; // Success
702739
}

src/pc_sampling.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,12 @@ void disablePCSampling(CUcontext context) {
111111
/*pPriv=*/NULL,
112112
/*ctx=*/context,
113113
};
114-
proton::cupti::pcSamplingDisable<true>(&params);
114+
// Use <false>: invoked from a libcupti callback whose caller wasn't built
115+
// with C++ EH, so a throw here would propagate up and abort the process.
116+
auto ret = proton::cupti::pcSamplingDisable<false>(&params);
117+
if (ret != CUPTI_SUCCESS) {
118+
DEBUG_PRINTF("cuptiPCSamplingDisable failed: %d (ctx=%p)\n", ret, context);
119+
}
115120
}
116121

117122
// Returns CUPTI_SUCCESS on success, or the raw CUptiResult on failure so

0 commit comments

Comments
 (0)