diff --git a/sycl/plugins/level_zero/pi_level_zero.cpp b/sycl/plugins/level_zero/pi_level_zero.cpp index e4402a8bb18df..18bce8362703d 100644 --- a/sycl/plugins/level_zero/pi_level_zero.cpp +++ b/sycl/plugins/level_zero/pi_level_zero.cpp @@ -1240,6 +1240,7 @@ pi_result _pi_ze_event_list_t::createAndRetainPiZeEventList( if (EventListLength > 0) { for (pi_uint32 I = 0; I < EventListLength; I++) { + PI_ASSERT(EventList[I] != nullptr, PI_INVALID_VALUE); auto ZeEvent = EventList[I]->ZeEvent; if (FilterEventWaitList) { diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 7e62b0ff18ba1..7324a1f82888b 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -160,8 +160,11 @@ static std::string commandToName(Command::CommandType Type) { static std::vector getPiEvents(const std::vector &EventImpls) { std::vector RetPiEvents; - for (auto &EventImpl : EventImpls) - RetPiEvents.push_back(EventImpl->getHandleRef()); + for (auto &EventImpl : EventImpls) { + if (EventImpl->getHandleRef() != nullptr) + RetPiEvents.push_back(EventImpl->getHandleRef()); + } + return RetPiEvents; } @@ -2231,12 +2234,12 @@ cl_int ExecCGCommand::enqueueImp() { case CG::CGTYPE::BarrierWaitlist: { CGBarrier *Barrier = static_cast(MCommandGroup.get()); std::vector Events = Barrier->MEventsWaitWithBarrier; - if (MQueue->get_device().is_host() || Events.empty()) { + std::vector PiEvents = getPiEvents(Events); + if (MQueue->get_device().is_host() || PiEvents.empty()) { // NOP for host device. // If Events is empty, then the barrier has no effect. return PI_SUCCESS; } - std::vector PiEvents = getPiEvents(Events); const detail::plugin &Plugin = MQueue->getPlugin(); Plugin.call( MQueue->getHandleRef(), PiEvents.size(), &PiEvents[0], &Event); diff --git a/sycl/unittests/scheduler/CMakeLists.txt b/sycl/unittests/scheduler/CMakeLists.txt index fd62dd40da843..221eaa2e90c22 100644 --- a/sycl/unittests/scheduler/CMakeLists.txt +++ b/sycl/unittests/scheduler/CMakeLists.txt @@ -1,5 +1,6 @@ add_sycl_unittest(SchedulerTests OBJECT BlockedCommands.cpp + Commands.cpp FailedCommands.cpp FinishedCmdCleanup.cpp LeafLimit.cpp diff --git a/sycl/unittests/scheduler/Commands.cpp b/sycl/unittests/scheduler/Commands.cpp new file mode 100644 index 0000000000000..aaab8029695f6 --- /dev/null +++ b/sycl/unittests/scheduler/Commands.cpp @@ -0,0 +1,93 @@ +//==----------- Commands.cpp --- Commands unit tests -----------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SchedulerTest.hpp" +#include "SchedulerTestUtils.hpp" +#include + +#include + +using namespace cl::sycl; + +pi_result redefinePiEnqueueEventsWaitWithBarrier(pi_queue Queue, + pi_uint32 NumEventsInWaitList, + const pi_event *EventWaitList, + pi_event *Event) { + + for (pi_uint32 i = 0; i != NumEventsInWaitList; ++i) + EXPECT_NE(EventWaitList[i], nullptr); + + return PI_SUCCESS; +} + +// Hack that allows to return a context in redefinePiEventGetInfo +RT::PiContext queue_global_context = nullptr; + +pi_result redefinePiEventGetInfo(pi_event, pi_event_info, size_t, + void *param_value, size_t *) { + *reinterpret_cast(param_value) = queue_global_context; + return PI_SUCCESS; +} + +pi_result redefinePiEventRetain(pi_event) { return PI_SUCCESS; } + +pi_result redefinePiEventRelease(pi_event) { return PI_SUCCESS; } + +// +// This test checks a handling of empty events in WaitWithBarrier command. +// Original reproducer for l0 plugin led to segfault(nullptr dereference): +// +// #include +// int main() { +// sycl::queue q; +// sycl::event e; +// q.submit_barrier({e}); +// } +// +TEST_F(SchedulerTest, WaitEmptyEventWithBarrier) { + // NB! This test requires at least one non-host environmet + // For example, OpenCL. + default_selector Selector{}; + if (Selector.select_device().is_host()) { + std::cerr << "Not run due to host-only environment\n"; + return; + } + + platform Plt{Selector}; + unittest::PiMock Mock{Plt}; + + Mock.redefine( + redefinePiEnqueueEventsWaitWithBarrier); + + queue Queue{Plt.get_devices()[0]}; + cl::sycl::detail::QueueImplPtr QueueImpl = detail::getSyclObjImpl(Queue); + + queue_global_context = + detail::getSyclObjImpl(Queue.get_context())->getHandleRef(); + + Mock.redefine(redefinePiEventGetInfo); + Mock.redefine(redefinePiEventRetain); + Mock.redefine(redefinePiEventRelease); + + auto EmptyEvent = std::make_shared(); + auto Event = std::make_shared( + reinterpret_cast(0x01), Queue.get_context()); + + using EventList = std::vector; + std::vector InputEventWaitLists = { + {EmptyEvent}, {Event, Event}, {EmptyEvent, Event}}; + + MockScheduler MS; + + for (auto &Arg : InputEventWaitLists) { + std::unique_ptr CommandGroup( + new detail::CGBarrier(std::move(Arg), {}, {}, {}, {}, {}, + detail::CG::CGTYPE::BarrierWaitlist, {})); + MS.Scheduler::addCG(std::move(CommandGroup), QueueImpl); + } +}