diff --git a/runtime/os_interface/linux/drm_memory_manager.cpp b/runtime/os_interface/linux/drm_memory_manager.cpp index da50395b53..324e3de5e0 100644 --- a/runtime/os_interface/linux/drm_memory_manager.cpp +++ b/runtime/os_interface/linux/drm_memory_manager.cpp @@ -472,6 +472,7 @@ uint64_t DrmMemoryManager::getInternalHeapBaseAddress() { MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStorage &handleStorage) { BufferObject *allocatedBos[max_fragments_count]; size_t numberOfBosAllocated = 0; + uint32_t indexesOfAllocatedBos[max_fragments_count]; for (unsigned int i = 0; i < max_fragments_count; i++) { // If there is no fragment it means it already exists. @@ -489,6 +490,7 @@ MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStor } allocatedBos[numberOfBosAllocated] = handleStorage.fragmentStorageData[i].osHandleStorage->bo; + indexesOfAllocatedBos[numberOfBosAllocated] = i; numberOfBosAllocated++; hostPtrManager.storeFragment(handleStorage.fragmentStorageData[i]); @@ -499,6 +501,9 @@ MemoryManager::AllocationStatus DrmMemoryManager::populateOsHandles(OsHandleStor int result = pinBB->pin(allocatedBos, numberOfBosAllocated); if (result == EFAULT) { + for (uint32_t i = 0; i < numberOfBosAllocated; i++) { + handleStorage.fragmentStorageData[indexesOfAllocatedBos[i]].freeTheFragment = true; + } return AllocationStatus::InvalidHostPointer; } else if (result != 0) { return AllocationStatus::Error; diff --git a/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp b/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp index c6e8aa8f95..2bd6b4b175 100644 --- a/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp +++ b/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp @@ -2571,3 +2571,49 @@ TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenForcePinNotAllowedAndH ::alignedFree(ptr); } + +TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, givenEnabledValidateHostMemoryWhenReadOnlyPointerCausesPinningFailWithEfaultThenPopulateOsHandlesMarksFragmentsToFree) { + std::unique_ptr testedMemoryManager(new TestedDrmMemoryManager(this->mock, false, true)); + ASSERT_NE(nullptr, testedMemoryManager.get()); + ASSERT_NE(nullptr, testedMemoryManager->getPinBB()); + + mock->reset(); + + DrmMockCustom::IoctlResExt ioctlResExt = {2, -1}; + mock->ioctl_res_ext = &ioctlResExt; + mock->errnoValue = EFAULT; + mock->ioctl_expected.gemUserptr = 2; + mock->ioctl_expected.execbuffer2 = 1; + + OsHandleStorage handleStorage; + OsHandle handle1; + handleStorage.fragmentStorageData[0].osHandleStorage = &handle1; + handleStorage.fragmentStorageData[0].cpuPtr = (void *)0x1000; + handleStorage.fragmentStorageData[0].fragmentSize = 4096; + + handleStorage.fragmentStorageData[1].osHandleStorage = nullptr; + handleStorage.fragmentStorageData[1].cpuPtr = (void *)0x2000; + handleStorage.fragmentStorageData[1].fragmentSize = 8192; + + handleStorage.fragmentStorageData[2].osHandleStorage = nullptr; + handleStorage.fragmentStorageData[2].cpuPtr = (void *)0x4000; + handleStorage.fragmentStorageData[2].fragmentSize = 4096; + + auto result = testedMemoryManager->populateOsHandles(handleStorage); + EXPECT_EQ(MemoryManager::AllocationStatus::InvalidHostPointer, result); + + mock->testIoctls(); + + EXPECT_NE(nullptr, handleStorage.fragmentStorageData[0].osHandleStorage); + EXPECT_NE(nullptr, handleStorage.fragmentStorageData[1].osHandleStorage); + EXPECT_NE(nullptr, handleStorage.fragmentStorageData[2].osHandleStorage); + + EXPECT_TRUE(handleStorage.fragmentStorageData[1].freeTheFragment); + EXPECT_TRUE(handleStorage.fragmentStorageData[2].freeTheFragment); + + handleStorage.fragmentStorageData[0].freeTheFragment = false; + handleStorage.fragmentStorageData[1].freeTheFragment = true; + handleStorage.fragmentStorageData[2].freeTheFragment = true; + + testedMemoryManager->cleanOsHandles(handleStorage); +}