[SYCL] Keep adapter_impl alive via shared_ptr while Managed handles exist
Managed<ur_program/kernel_handle_t> stored a raw adapter_impl* and released
its UR resource in ~Managed through that pointer. Adapters were owned by
GlobalHandler as raw new/delete and freed in unloadAdapters(). A cached or
in-flight Managed (e.g. the program build result kept in a context's
KernelProgramCache, or a discarded getBuiltURProgram() retain() temporary)
could outlive adapter teardown and call urProgramRelease through a freed
adapter -> use-after-free. On Windows/icx the freed adapter's func-ptr table
reads back null, so the call jumps to 0x0 (SEH 0xC0000005); on other configs
the freed memory stayed usable and the bug was latent.
Own adapters with shared_ptr and have Managed hold a shared_ptr<adapter_impl>
(via enable_shared_from_this) so the adapter cannot be destroyed while any
Managed referencing it is alive. unloadAdapters() now only releases the UR
adapter and drops the owning refs; the C++ object lives until the last Managed
is gone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>