Skip to content

Commit 4ab4766

Browse files
committed
Fix possible crashes with kernel objects
Getting a named kernel from a kernel bundle that does not contain it could cause a crash. It was also possible for a kernel bundle wrapping a NULL reference, which could then be submitted and crash
1 parent 8890726 commit 4ab4766

4 files changed

Lines changed: 116 additions & 11 deletions

File tree

‎dpctl/compiler/_compiler.pyx‎

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -270,18 +270,45 @@ cdef class SyclKernelBundle:
270270
return self._kernel_bundle_ref
271271

272272
cpdef SyclKernel get_sycl_kernel(self, str kernel_name):
273-
name = kernel_name.encode("utf8")
273+
"""get_sycl_kernel(kernel_name)
274+
275+
Returns the kernel with the given name defined in this kernel bundle.
276+
277+
Args:
278+
kernel_name (str):
279+
Name of the kernel, as it appears in the kernel bundle. For a
280+
bundle created from a SPIR-V binary this is the name of the
281+
entry point, which for a kernel written in SYCL is the mangled
282+
name of its kernel class, e.g.
283+
``'_ZTS20BasicSpecConstKernel'``.
284+
285+
Returns:
286+
dpctl.compiler.SyclKernel:
287+
The kernel object.
288+
289+
Raises:
290+
ValueError:
291+
If the kernel could not be created for any reason.
292+
"""
293+
cdef bytes name = kernel_name.encode("utf8")
294+
cdef DPCTLSyclKernelRef KRef = NULL
295+
274296
if self._is_sycl_source:
275-
return SyclKernel._create(
276-
DPCTLKernelBundle_GetSyclKernel(
277-
self._kernel_bundle_ref, name
278-
),
279-
kernel_name
280-
)
281-
return SyclKernel._create(
282-
DPCTLKernelBundle_GetKernel(self._kernel_bundle_ref, name),
283-
kernel_name
284-
)
297+
KRef = DPCTLKernelBundle_GetSyclKernel(
298+
self._kernel_bundle_ref, name
299+
)
300+
else:
301+
KRef = DPCTLKernelBundle_GetKernel(self._kernel_bundle_ref, name)
302+
if KRef is NULL:
303+
# returning a SyclKernel with a NULL reference would defer the
304+
# failure to the submission of the kernel
305+
raise ValueError(
306+
f"Kernel '{kernel_name}' could not be created from the kernel "
307+
"bundle. The kernel bundle may not define a kernel with that "
308+
"name, or the module it was built from may require device "
309+
"libraries that were not linked into it."
310+
)
311+
return SyclKernel._create(KRef, kernel_name)
285312

286313
def has_sycl_kernel(self, str kernel_name):
287314
name = kernel_name.encode("utf8")

‎dpctl/tests/test_sycl_compiler.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,21 @@ def test_create_kernel_bundle_from_source_ocl():
233233
_check_multi_kernel_bundle(kb)
234234

235235

236+
def test_get_sycl_kernel_undefined_name():
237+
try:
238+
q = dpctl.SyclQueue()
239+
except dpctl.SyclQueueCreationError:
240+
pytest.skip("Could not create default queue")
241+
spirv_file = get_spirv_abspath("multi_kernel.spv")
242+
with open(spirv_file, "rb") as fin:
243+
spirv = fin.read()
244+
kb = dpc.create_kernel_bundle_from_spirv(q, spirv)
245+
246+
assert not kb.has_sycl_kernel("no_such_kernel")
247+
with pytest.raises(ValueError):
248+
kb.get_sycl_kernel("no_such_kernel")
249+
250+
236251
def test_create_kernel_bundle_from_spirv_ocl():
237252
q = _get_opencl_queue_or_skip()
238253
spirv_file = get_spirv_abspath("multi_kernel.spv")

‎libsyclinterface/source/dpctl_sycl_queue_interface.cpp‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,17 @@ DPCTLQueue_SubmitRange(__dpctl_keep const DPCTLSyclKernelRef KRef,
498498
__dpctl_keep const DPCTLSyclEventRef *DepEvents,
499499
size_t NDepEvents)
500500
{
501+
if (!KRef) {
502+
error_handler("Cannot submit the kernel as the kernel is a nullptr.",
503+
__FILE__, __func__, __LINE__, error_level::error);
504+
return nullptr;
505+
}
506+
if (!QRef) {
507+
error_handler("Cannot submit the kernel as the queue is a nullptr.",
508+
__FILE__, __func__, __LINE__, error_level::error);
509+
return nullptr;
510+
}
511+
501512
auto Kernel = unwrap<kernel>(KRef);
502513
auto Queue = unwrap<queue>(QRef);
503514
event e;
@@ -563,6 +574,17 @@ DPCTLQueue_SubmitNDRange(__dpctl_keep const DPCTLSyclKernelRef KRef,
563574
__dpctl_keep const DPCTLSyclEventRef *DepEvents,
564575
size_t NDepEvents)
565576
{
577+
if (!KRef) {
578+
error_handler("Cannot submit the kernel as the kernel is a nullptr.",
579+
__FILE__, __func__, __LINE__, error_level::error);
580+
return nullptr;
581+
}
582+
if (!QRef) {
583+
error_handler("Cannot submit the kernel as the queue is a nullptr.",
584+
__FILE__, __func__, __LINE__, error_level::error);
585+
return nullptr;
586+
}
587+
566588
auto Kernel = unwrap<kernel>(KRef);
567589
auto Queue = unwrap<queue>(QRef);
568590
event e;

‎libsyclinterface/tests/test_sycl_queue_submit.cpp‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,47 @@ TEST_F(TestQueueSubmit, CheckForUnsupportedArgTy)
389389
ASSERT_TRUE(ERef == nullptr);
390390
}
391391

392+
TEST_F(TestQueueSubmit, CheckForNullKernel)
393+
{
394+
std::size_t Range[] = {SIZE};
395+
std::size_t lRange[] = {1};
396+
std::size_t RANGE_NDIMS = 1;
397+
DPCTLSyclEventRef ERef = nullptr;
398+
399+
EXPECT_NO_FATAL_FAILURE(
400+
ERef = DPCTLQueue_SubmitRange(nullptr, QRef, nullptr, nullptr, 0, Range,
401+
RANGE_NDIMS, nullptr, 0));
402+
ASSERT_TRUE(ERef == nullptr);
403+
404+
EXPECT_NO_FATAL_FAILURE(ERef = DPCTLQueue_SubmitNDRange(
405+
nullptr, QRef, nullptr, nullptr, 0, Range,
406+
lRange, RANGE_NDIMS, nullptr, 0));
407+
ASSERT_TRUE(ERef == nullptr);
408+
}
409+
410+
TEST_F(TestQueueSubmit, CheckForNullQueue)
411+
{
412+
std::size_t Range[] = {SIZE};
413+
std::size_t lRange[] = {1};
414+
std::size_t RANGE_NDIMS = 1;
415+
DPCTLSyclEventRef ERef = nullptr;
416+
417+
auto kernel = DPCTLKernelBundle_GetKernel(KBRef, "_ZTS11RangeKernelIiE");
418+
ASSERT_TRUE(kernel != nullptr);
419+
420+
EXPECT_NO_FATAL_FAILURE(
421+
ERef = DPCTLQueue_SubmitRange(kernel, nullptr, nullptr, nullptr, 0,
422+
Range, RANGE_NDIMS, nullptr, 0));
423+
ASSERT_TRUE(ERef == nullptr);
424+
425+
EXPECT_NO_FATAL_FAILURE(ERef = DPCTLQueue_SubmitNDRange(
426+
kernel, nullptr, nullptr, nullptr, 0, Range,
427+
lRange, RANGE_NDIMS, nullptr, 0));
428+
ASSERT_TRUE(ERef == nullptr);
429+
430+
EXPECT_NO_FATAL_FAILURE(DPCTLKernel_Delete(kernel));
431+
}
432+
392433
struct TestQueueSubmitBarrier : public ::testing::Test
393434
{
394435
DPCTLSyclQueueRef QRef = nullptr;

0 commit comments

Comments
 (0)