[SYCL] Don't skip memory-record removal when buffer write-back throws (#23082)
## Problem
`SYCLMemObjT::updateHostMemory()` performs the write-back and then
detaches the memory object from the scheduler:
```cpp
void SYCLMemObjT::updateHostMemory() {
if ((MUploadDataFunctor != nullptr) && MNeedWriteBack &&
GlobalHandler::instance().isOkToDefer())
MUploadDataFunctor(); // <-- can throw
if (MRecord) {
bool Result = Scheduler::getInstance().removeMemoryObject(...);
...
}
releaseHostMem(MShadowCopy);
...
}
```
`MUploadDataFunctor()` ends up in `Scheduler::addCopyBack()` followed by
`Event->wait()`, and a failing copy-back throws from
`GraphProcessor::waitForEvent()`. The exception then propagates out of
`updateHostMemory()`, so **`removeMemoryObject()`, `releaseHostMem()`
and the interop `urMemRelease()` below it are all skipped**. Both
callers (`~buffer_impl` and `~image_impl`) wrap the call in `try { ... }
catch (...) {}`, so the failure is silently discarded and the object is
destroyed with its scheduler record still attached.
The leaked set is the whole `MemObjRecord`: its
alloca/release/copy-back/exec commands, the `LeavesCollection`, and —
because `Command::MQueue` is a `shared_ptr<queue_impl>` — the queue and
its context with the kernel/program caches. LeakSanitizer reported 41
allocations / ~10.7 KB for a single occurrence
(`SchedulerTest.FailedCopyBackException`), all of them *indirect* leaks
with no direct leak, which is the signature of an orphaned graph rather
than a forgotten `delete`.
## Fix
Contain the failure so the teardown below always runs:
```cpp
if ((MUploadDataFunctor != nullptr) && MNeedWriteBack &&
GlobalHandler::instance().isOkToDefer()) {
// A failing write-back is reported as an asynchronous exception by
// Scheduler::addCopyBack and must not skip the removal of the memory
// record below, otherwise the record and the commands it owns are leaked.
try {
MUploadDataFunctor();
} catch (...) {
}
}
```
Observable behavior is unchanged: both existing callers already
discarded this exception, and the failure is still reported to the user
through the asynchronous exception `Scheduler::addCopyBack()` records.
---
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>