From e4cadad4834040ab528b81d214c9f3b8e1fd33cb Mon Sep 17 00:00:00 2001 From: Krzysztof Bogacki Date: Thu, 21 Mar 2024 21:52:49 +0100 Subject: [PATCH 1/2] nvapi: Guard against null device in Reflex calls --- src/d3d/nvapi_d3d_low_latency_device.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/d3d/nvapi_d3d_low_latency_device.cpp b/src/d3d/nvapi_d3d_low_latency_device.cpp index bff43cd3..2debeb8d 100644 --- a/src/d3d/nvapi_d3d_low_latency_device.cpp +++ b/src/d3d/nvapi_d3d_low_latency_device.cpp @@ -48,6 +48,9 @@ namespace dxvk { } Com NvapiD3dLowLatencyDevice::GetLowLatencyDevice(IUnknown* device) { + if (device == nullptr) + return nullptr; + std::scoped_lock lock(m_LowLatencyDeviceMutex); auto it = m_lowLatencyDeviceMap.find(device); if (it != m_lowLatencyDeviceMap.end()) From cf570aacbf68d61e4c5b995ea4adcef2a3614c31 Mon Sep 17 00:00:00 2001 From: Krzysztof Bogacki Date: Fri, 22 Mar 2024 00:26:00 +0100 Subject: [PATCH 2/2] nvapi: Return appropriate error codes from Reflex entry points when passed null pointers --- src/nvapi_d3d.cpp | 15 +++++++++++++++ src/nvapi_d3d12.cpp | 4 ++-- tests/nvapi_d3d.cpp | 33 +++++++++++++++++++++++++++++++++ tests/nvapi_d3d12.cpp | 17 +++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/nvapi_d3d.cpp b/src/nvapi_d3d.cpp index 166abc06..ed11ebb0 100644 --- a/src/nvapi_d3d.cpp +++ b/src/nvapi_d3d.cpp @@ -115,6 +115,9 @@ extern "C" { if (nvapiAdapterRegistry == nullptr) return ApiNotInitialized(n); + if (pDevice == nullptr) + return InvalidArgument(n); + if (!nvapiD3dInstance->IsReflexAvailable(pDevice)) return NoImplementation(n, alreadyLoggedNoReflex); @@ -135,6 +138,9 @@ extern "C" { if (pSetSleepModeParams->version != NV_SET_SLEEP_MODE_PARAMS_VER1) return IncompatibleStructVersion(n); + if (pDevice == nullptr) + return InvalidArgument(n); + if (!nvapiD3dInstance->IsReflexAvailable(pDevice)) return NoImplementation(n, alreadyLoggedNoReflex); @@ -155,6 +161,9 @@ extern "C" { if (pGetSleepStatusParams->version != NV_GET_SLEEP_STATUS_PARAMS_VER1) return IncompatibleStructVersion(n); + if (pDevice == nullptr) + return InvalidArgument(n); + if (!nvapiD3dInstance->IsReflexAvailable(pDevice)) return NoImplementation(n, alreadyLoggedNoReflex); @@ -175,6 +184,9 @@ extern "C" { if (pGetLatencyParams->version != NV_LATENCY_RESULT_PARAMS_VER1) return IncompatibleStructVersion(n); + if (pDev == nullptr) + return InvalidArgument(n); + if (nvapiD3dInstance->IsUsingLfx() || !NvapiD3dLowLatencyDevice::SupportsLowLatency(pDev)) return NoImplementation(n, alreadyLoggedNoImpl); @@ -196,6 +208,9 @@ extern "C" { if (pSetLatencyMarkerParams->version != NV_LATENCY_MARKER_PARAMS_VER1) return IncompatibleStructVersion(n); + if (pDev == nullptr) + return InvalidArgument(n); + if (nvapiD3dInstance->IsUsingLfx() || !NvapiD3dLowLatencyDevice::SupportsLowLatency(pDev)) return NoImplementation(n, alreadyLoggedNoImpl); diff --git a/src/nvapi_d3d12.cpp b/src/nvapi_d3d12.cpp index 49482d7a..b5f61c43 100644 --- a/src/nvapi_d3d12.cpp +++ b/src/nvapi_d3d12.cpp @@ -408,7 +408,7 @@ extern "C" { return ApiNotInitialized(n); if (pCommandQueue == nullptr) - return InvalidArgument(n); + return InvalidPointer(n); ID3D12Device* pDevice; if (FAILED(pCommandQueue->GetDevice(IID_PPV_ARGS(&pDevice)))) @@ -435,7 +435,7 @@ extern "C" { return IncompatibleStructVersion(n); if (pCommandQueue == nullptr) - return InvalidArgument(n); + return InvalidPointer(n); ID3D12Device* pDevice; if (FAILED(pCommandQueue->GetDevice(IID_PPV_ARGS(&pDevice)))) diff --git a/tests/nvapi_d3d.cpp b/tests/nvapi_d3d.cpp index 40cf0a47..66e63ee0 100644 --- a/tests/nvapi_d3d.cpp +++ b/tests/nvapi_d3d.cpp @@ -129,6 +129,39 @@ TEST_CASE("D3D Reflex/LatencyFleX depending methods succeed", "[.d3d]") { ALLOW_CALL(*lfx, IsAvailable()) .RETURN(false); + SECTION("Reflex methods fail when given null device") { + SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx)); + REQUIRE(NvAPI_Initialize() == NVAPI_OK); + + SECTION("GetSleepStatus returns invalid-argument") { + NV_GET_SLEEP_STATUS_PARAMS_V1 params{}; + params.version = NV_GET_SLEEP_STATUS_PARAMS_VER1; + REQUIRE(NvAPI_D3D_GetSleepStatus(nullptr, ¶ms) == NVAPI_INVALID_ARGUMENT); + } + + SECTION("SetSleepMode returns invalid-argument") { + NV_SET_SLEEP_MODE_PARAMS params{}; + params.version = NV_SET_SLEEP_MODE_PARAMS_VER; + REQUIRE(NvAPI_D3D_SetSleepMode(nullptr, ¶ms) == NVAPI_INVALID_ARGUMENT); + } + + SECTION("Sleep returns invalid-argument") { + REQUIRE(NvAPI_D3D_Sleep(nullptr) == NVAPI_INVALID_ARGUMENT); + } + + SECTION("GetLatency returns invalid-argument") { + NV_LATENCY_RESULT_PARAMS params; + params.version = NV_LATENCY_RESULT_PARAMS_VER; + REQUIRE(NvAPI_D3D_GetLatency(nullptr, ¶ms) == NVAPI_INVALID_ARGUMENT); + } + + SECTION("SetLatencyMarker returns invalid-argument") { + NV_LATENCY_MARKER_PARAMS params; + params.version = NV_LATENCY_MARKER_PARAMS_VER; + REQUIRE(NvAPI_D3D_SetLatencyMarker(nullptr, ¶ms) == NVAPI_INVALID_ARGUMENT); + } + } + SECTION("LatencyFleX depending methods succeed when LFX is available") { ALLOW_CALL(*lfx, IsAvailable()) .RETURN(true); diff --git a/tests/nvapi_d3d12.cpp b/tests/nvapi_d3d12.cpp index f57c1cf9..103d71a0 100644 --- a/tests/nvapi_d3d12.cpp +++ b/tests/nvapi_d3d12.cpp @@ -821,6 +821,13 @@ TEST_CASE("D3D12 methods succeed", "[.d3d12]") { REQUIRE(NvAPI_Initialize() == NVAPI_OK); REQUIRE(NvAPI_D3D12_NotifyOutOfBandCommandQueue(&commandQueue, OUT_OF_BAND_RENDER) == NVAPI_NO_IMPLEMENTATION); } + + SECTION("NotifyOutOfBandCommandQueue with null command queue returns invalid-pointer") { + SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx)); + + REQUIRE(NvAPI_Initialize() == NVAPI_OK); + REQUIRE(NvAPI_D3D12_NotifyOutOfBandCommandQueue(nullptr, OUT_OF_BAND_RENDER) == NVAPI_INVALID_POINTER); + } } SECTION("SetAsyncFrameMarker succeeds") { @@ -874,6 +881,16 @@ TEST_CASE("D3D12 methods succeed", "[.d3d12]") { params.version = NV_LATENCY_MARKER_PARAMS_VER; REQUIRE(NvAPI_D3D12_SetAsyncFrameMarker(&commandQueue, ¶ms) != NVAPI_INCOMPATIBLE_STRUCT_VERSION); } + + SECTION("SetAsyncFrameMarker with null command queue returns invalid-pointer") { + SetupResourceFactory(std::move(dxgiFactory), std::move(vulkan), std::move(nvml), std::move(lfx)); + + REQUIRE(NvAPI_Initialize() == NVAPI_OK); + + NV_LATENCY_MARKER_PARAMS params{}; + params.version = NV_LATENCY_MARKER_PARAMS_VER; + REQUIRE(NvAPI_D3D12_SetAsyncFrameMarker(nullptr, ¶ms) == NVAPI_INVALID_POINTER); + } } } }