Skip to content

Commit 3040061

Browse files
[SYCL] no exceptions leaking from destructors (#14273)
Destructors are implicitly noexcept, so we must ensure they don't actually throw exceptions. No change to API or ABI with this PR.
1 parent 088bea6 commit 3040061

File tree

16 files changed

+196
-104
lines changed

16 files changed

+196
-104
lines changed

sycl/include/sycl/buffer.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,13 @@ class buffer : public detail::buffer_plain,
472472

473473
buffer &operator=(buffer &&rhs) = default;
474474

475-
~buffer() { buffer_plain::handleRelease(); }
475+
~buffer() {
476+
try {
477+
buffer_plain::handleRelease();
478+
} catch (std::exception &e) {
479+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~buffer", e);
480+
}
481+
}
476482

477483
bool operator==(const buffer &rhs) const { return impl == rhs.impl; }
478484

sycl/include/sycl/detail/common.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,17 @@ static constexpr std::array<T, N> RepeatValue(const T &Arg) {
368368
return RepeatValueHelper(Arg, std::make_index_sequence<N>());
369369
}
370370

371+
// to output exceptions caught in ~destructors
372+
#ifndef NDEBUG
373+
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e) \
374+
{ \
375+
std::cerr << str << " " << e.what() << std::endl; \
376+
assert(false); \
377+
}
378+
#else
379+
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e)
380+
#endif
381+
371382
} // namespace detail
372383
} // namespace _V1
373384
} // namespace sycl

sycl/include/sycl/image.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,12 @@ class unsampled_image
954954
unsampled_image &operator=(unsampled_image &&rhs) = default;
955955

956956
~unsampled_image() {
957-
common_base::unsampledImageDestructorNotification((void *)this->impl.get());
957+
try {
958+
common_base::unsampledImageDestructorNotification(
959+
(void *)this->impl.get());
960+
} catch (std::exception &e) {
961+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~unsampled_image", e);
962+
}
958963
}
959964

960965
bool operator==(const unsampled_image &rhs) const {
@@ -1095,7 +1100,11 @@ class sampled_image
10951100
sampled_image &operator=(sampled_image &&rhs) = default;
10961101

10971102
~sampled_image() {
1098-
common_base::sampledImageDestructorNotification((void *)this->impl.get());
1103+
try {
1104+
common_base::sampledImageDestructorNotification((void *)this->impl.get());
1105+
} catch (std::exception &e) {
1106+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~sampled_image", e);
1107+
}
10991108
}
11001109

11011110
bool operator==(const sampled_image &rhs) const {

sycl/include/syclcompat/device.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,13 @@ class device_ext : public sycl::device {
339339
public:
340340
device_ext() : sycl::device(), _ctx(*this) {}
341341
~device_ext() {
342-
std::lock_guard<std::mutex> lock(m_mutex);
343-
sycl::event::wait(_events);
344-
_queues.clear();
342+
try {
343+
std::lock_guard<std::mutex> lock(m_mutex);
344+
sycl::event::wait(_events);
345+
_queues.clear();
346+
} catch (std::exception &e) {
347+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~device_ext", e);
348+
}
345349
}
346350
device_ext(const sycl::device &base, bool print_on_async_exceptions = false,
347351
bool in_order = true)

sycl/source/detail/context_impl.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -145,23 +145,27 @@ cl_context context_impl::get() const {
145145
bool context_impl::is_host() const { return MHostContext; }
146146

147147
context_impl::~context_impl() {
148-
// Free all events associated with the initialization of device globals.
149-
for (auto &DeviceGlobalInitializer : MDeviceGlobalInitializers)
150-
DeviceGlobalInitializer.second.ClearEvents(getPlugin());
151-
// Free all device_global USM allocations associated with this context.
152-
for (const void *DeviceGlobal : MAssociatedDeviceGlobals) {
153-
DeviceGlobalMapEntry *DGEntry =
154-
detail::ProgramManager::getInstance().getDeviceGlobalEntry(
155-
DeviceGlobal);
156-
DGEntry->removeAssociatedResources(this);
157-
}
158-
for (auto LibProg : MCachedLibPrograms) {
159-
assert(LibProg.second && "Null program must not be kept in the cache");
160-
getPlugin()->call<PiApiKind::piProgramRelease>(LibProg.second);
161-
}
162-
if (!MHostContext) {
163-
// TODO catch an exception and put it to list of asynchronous exceptions
164-
getPlugin()->call_nocheck<PiApiKind::piContextRelease>(MContext);
148+
try {
149+
// Free all events associated with the initialization of device globals.
150+
for (auto &DeviceGlobalInitializer : MDeviceGlobalInitializers)
151+
DeviceGlobalInitializer.second.ClearEvents(getPlugin());
152+
// Free all device_global USM allocations associated with this context.
153+
for (const void *DeviceGlobal : MAssociatedDeviceGlobals) {
154+
DeviceGlobalMapEntry *DGEntry =
155+
detail::ProgramManager::getInstance().getDeviceGlobalEntry(
156+
DeviceGlobal);
157+
DGEntry->removeAssociatedResources(this);
158+
}
159+
for (auto LibProg : MCachedLibPrograms) {
160+
assert(LibProg.second && "Null program must not be kept in the cache");
161+
getPlugin()->call<PiApiKind::piProgramRelease>(LibProg.second);
162+
}
163+
if (!MHostContext) {
164+
// TODO catch an exception and put it to list of asynchronous exceptions
165+
getPlugin()->call<PiApiKind::piContextRelease>(MContext);
166+
}
167+
} catch (std::exception &e) {
168+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~context_impl", e);
165169
}
166170
}
167171

sycl/source/detail/device_image_impl.hpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -300,15 +300,18 @@ class device_image_impl {
300300
}
301301

302302
~device_image_impl() {
303-
304-
if (MProgram) {
305-
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
306-
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
307-
}
308-
if (MSpecConstsBuffer) {
309-
std::lock_guard<std::mutex> Lock{MSpecConstAccessMtx};
310-
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
311-
memReleaseHelper(Plugin, MSpecConstsBuffer);
303+
try {
304+
if (MProgram) {
305+
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
306+
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
307+
}
308+
if (MSpecConstsBuffer) {
309+
std::lock_guard<std::mutex> Lock{MSpecConstAccessMtx};
310+
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
311+
memReleaseHelper(Plugin, MSpecConstsBuffer);
312+
}
313+
} catch (std::exception &e) {
314+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~device_image_impl", e);
312315
}
313316
}
314317

sycl/source/detail/event_impl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@ bool event_impl::is_host() {
5454
}
5555

5656
event_impl::~event_impl() {
57-
if (MEvent)
58-
getPlugin()->call<PiApiKind::piEventRelease>(MEvent);
57+
try {
58+
if (MEvent)
59+
getPlugin()->call<PiApiKind::piEventRelease>(MEvent);
60+
} catch (std::exception &e) {
61+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~event_impl", e);
62+
}
5963
}
6064

6165
void event_impl::waitInternal(bool *Success) {

sycl/source/detail/global_handler.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,18 @@ class ObjectUsageCounter {
5454
MCounter++;
5555
}
5656
~ObjectUsageCounter() {
57-
if (!MModifyCounter)
58-
return;
59-
60-
LockGuard Guard(GlobalHandler::MSyclGlobalHandlerProtector);
61-
MCounter--;
62-
GlobalHandler *RTGlobalObjHandler = GlobalHandler::getInstancePtr();
63-
if (RTGlobalObjHandler) {
64-
RTGlobalObjHandler->prepareSchedulerToRelease(!MCounter);
57+
try {
58+
if (!MModifyCounter)
59+
return;
60+
61+
LockGuard Guard(GlobalHandler::MSyclGlobalHandlerProtector);
62+
MCounter--;
63+
GlobalHandler *RTGlobalObjHandler = GlobalHandler::getInstancePtr();
64+
if (RTGlobalObjHandler) {
65+
RTGlobalObjHandler->prepareSchedulerToRelease(!MCounter);
66+
}
67+
} catch (std::exception &e) {
68+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~ObjectUsageCounter", e);
6569
}
6670
}
6771

@@ -234,12 +238,17 @@ void GlobalHandler::releaseDefaultContexts() {
234238

235239
struct EarlyShutdownHandler {
236240
~EarlyShutdownHandler() {
241+
try {
237242
#ifdef _WIN32
238-
// on Windows we keep to the existing shutdown procedure
239-
GlobalHandler::instance().releaseDefaultContexts();
243+
// on Windows we keep to the existing shutdown procedure
244+
GlobalHandler::instance().releaseDefaultContexts();
240245
#else
241-
shutdown_early();
246+
shutdown_early();
242247
#endif
248+
} catch (std::exception &e) {
249+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~EarlyShutdownHandler",
250+
e);
251+
}
243252
}
244253
};
245254

sycl/source/detail/graph_impl.cpp

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,13 @@ void exec_graph_impl::makePartitions() {
297297
}
298298

299299
graph_impl::~graph_impl() {
300-
clearQueues();
301-
for (auto &MemObj : MMemObjs) {
302-
MemObj->markNoLongerBeingUsedInGraph();
300+
try {
301+
clearQueues();
302+
for (auto &MemObj : MMemObjs) {
303+
MemObj->markNoLongerBeingUsedInGraph();
304+
}
305+
} catch (std::exception &e) {
306+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~graph_impl", e);
303307
}
304308
}
305309

@@ -784,34 +788,38 @@ exec_graph_impl::exec_graph_impl(sycl::context Context,
784788
}
785789

786790
exec_graph_impl::~exec_graph_impl() {
787-
const sycl::detail::PluginPtr &Plugin =
788-
sycl::detail::getSyclObjImpl(MContext)->getPlugin();
789-
MSchedule.clear();
790-
// We need to wait on all command buffer executions before we can release
791-
// them.
792-
for (auto &Event : MExecutionEvents) {
793-
Event->wait(Event);
794-
}
791+
try {
792+
const sycl::detail::PluginPtr &Plugin =
793+
sycl::detail::getSyclObjImpl(MContext)->getPlugin();
794+
MSchedule.clear();
795+
// We need to wait on all command buffer executions before we can release
796+
// them.
797+
for (auto &Event : MExecutionEvents) {
798+
Event->wait(Event);
799+
}
795800

796-
for (const auto &Partition : MPartitions) {
797-
Partition->MSchedule.clear();
798-
for (const auto &Iter : Partition->MPiCommandBuffers) {
799-
if (auto CmdBuf = Iter.second; CmdBuf) {
801+
for (const auto &Partition : MPartitions) {
802+
Partition->MSchedule.clear();
803+
for (const auto &Iter : Partition->MPiCommandBuffers) {
804+
if (auto CmdBuf = Iter.second; CmdBuf) {
805+
pi_result Res = Plugin->call_nocheck<
806+
sycl::detail::PiApiKind::piextCommandBufferRelease>(CmdBuf);
807+
(void)Res;
808+
assert(Res == pi_result::PI_SUCCESS);
809+
}
810+
}
811+
}
812+
813+
for (auto &Iter : MCommandMap) {
814+
if (auto Command = Iter.second; Command) {
800815
pi_result Res = Plugin->call_nocheck<
801-
sycl::detail::PiApiKind::piextCommandBufferRelease>(CmdBuf);
816+
sycl::detail::PiApiKind::piextCommandBufferReleaseCommand>(Command);
802817
(void)Res;
803818
assert(Res == pi_result::PI_SUCCESS);
804819
}
805820
}
806-
}
807-
808-
for (auto &Iter : MCommandMap) {
809-
if (auto Command = Iter.second; Command) {
810-
pi_result Res = Plugin->call_nocheck<
811-
sycl::detail::PiApiKind::piextCommandBufferReleaseCommand>(Command);
812-
(void)Res;
813-
assert(Res == pi_result::PI_SUCCESS);
814-
}
821+
} catch (std::exception &e) {
822+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~exec_graph_impl", e);
815823
}
816824
}
817825

sycl/source/detail/kernel_impl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,13 @@ kernel_impl::kernel_impl(ContextImplPtr Context, ProgramImplPtr ProgramImpl)
7575
: MContext(Context), MProgram(ProgramImpl->getHandleRef()) {}
7676

7777
kernel_impl::~kernel_impl() {
78-
// TODO catch an exception and put it to list of asynchronous exceptions
79-
if (!is_host()) {
80-
getPlugin()->call<PiApiKind::piKernelRelease>(MKernel);
78+
try {
79+
// TODO catch an exception and put it to list of asynchronous exceptions
80+
if (!is_host()) {
81+
getPlugin()->call<PiApiKind::piKernelRelease>(MKernel);
82+
}
83+
} catch (std::exception &e) {
84+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~kernel_impl", e);
8185
}
8286
}
8387

sycl/source/detail/pi_utils.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,14 @@ struct OwnedPiEvent {
3131
MPlugin->call<PiApiKind::piEventRetain>(*MEvent);
3232
}
3333
~OwnedPiEvent() {
34-
// Release the event if the ownership was not transferred.
35-
if (MEvent.has_value())
36-
MPlugin->call<PiApiKind::piEventRelease>(*MEvent);
34+
try {
35+
// Release the event if the ownership was not transferred.
36+
if (MEvent.has_value())
37+
MPlugin->call<PiApiKind::piEventRelease>(*MEvent);
38+
39+
} catch (std::exception &e) {
40+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~OwnedPiEvent", e);
41+
}
3742
}
3843

3944
OwnedPiEvent(OwnedPiEvent &&Other)

sycl/source/detail/program_impl.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,14 @@ program_impl::program_impl(ContextImplPtr Context,
207207
}
208208

209209
program_impl::~program_impl() {
210-
// TODO catch an exception and put it to list of asynchronous exceptions
211-
if (!is_host() && MProgram != nullptr) {
212-
const PluginPtr &Plugin = getPlugin();
213-
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
210+
try {
211+
// TODO catch an exception and put it to list of asynchronous exceptions
212+
if (!is_host() && MProgram != nullptr) {
213+
const PluginPtr &Plugin = getPlugin();
214+
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
215+
}
216+
} catch (std::exception &e) {
217+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~program_impl", e);
214218
}
215219
}
216220

sycl/source/detail/queue_impl.hpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -314,25 +314,29 @@ class queue_impl {
314314
}
315315

316316
~queue_impl() {
317-
// The trace event created in the constructor should be active through the
318-
// lifetime of the queue object as member variables when ABI breakage is
319-
// allowed. This example shows MTraceEvent as a member variable.
317+
try {
318+
// The trace event created in the constructor should be active through the
319+
// lifetime of the queue object as member variables when ABI breakage is
320+
// allowed. This example shows MTraceEvent as a member variable.
320321
#if XPTI_ENABLE_INSTRUMENTATION
321-
constexpr uint16_t NotificationTraceType =
322-
static_cast<uint16_t>(xpti::trace_point_type_t::queue_destroy);
323-
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
324-
// Used cached information in member variables
325-
xptiNotifySubscribers(MStreamID, NotificationTraceType, nullptr,
326-
(xpti::trace_event_data_t *)MTraceEvent,
327-
MInstanceID,
328-
static_cast<const void *>("queue_destroy"));
329-
xptiReleaseEvent((xpti::trace_event_data_t *)MTraceEvent);
330-
}
322+
constexpr uint16_t NotificationTraceType =
323+
static_cast<uint16_t>(xpti::trace_point_type_t::queue_destroy);
324+
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
325+
// Used cached information in member variables
326+
xptiNotifySubscribers(MStreamID, NotificationTraceType, nullptr,
327+
(xpti::trace_event_data_t *)MTraceEvent,
328+
MInstanceID,
329+
static_cast<const void *>("queue_destroy"));
330+
xptiReleaseEvent((xpti::trace_event_data_t *)MTraceEvent);
331+
}
331332
#endif
332-
throw_asynchronous();
333-
if (!MHostQueue) {
334-
cleanup_fusion_cmd();
335-
getPlugin()->call<PiApiKind::piQueueRelease>(MQueues[0]);
333+
throw_asynchronous();
334+
if (!MHostQueue) {
335+
cleanup_fusion_cmd();
336+
getPlugin()->call<PiApiKind::piQueueRelease>(MQueues[0]);
337+
}
338+
} catch (std::exception &e) {
339+
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~queue_impl", e);
336340
}
337341
}
338342

0 commit comments

Comments
 (0)