[PATCH] dxgi: Avoid a double free in d3d11_swapchain_init().
Zhiyi Zhang
zzhang at codeweavers.com
Mon Feb 17 20:27:09 CST 2020
If IDXGISwapChain1_GetContainingOutput() or dxgi_swapchain_set_fullscreen_state() fails,
wined3d_swapchain_decref() is called to free the private store and d3d11_swapchain, which
are freed again later in d3d11_swapchain_init() and upper functions. In this error path,
there are also use-after-frees for a IDXGIFactory and IDXGIDevice. This error could be
produced by creating a swapchain using a device window on the secondary monitor as of now.
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/dxgi/swapchain.c | 4 ++--
dlls/wined3d/device.c | 9 +++++++++
dlls/wined3d/swapchain.c | 14 ++------------
dlls/wined3d/wined3d.spec | 1 +
include/wine/wined3d.h | 1 +
5 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index 004bd1457d..7ac5a881c2 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -898,7 +898,7 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi
&swapchain->target)))
{
WARN("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr);
- wined3d_swapchain_decref(swapchain->wined3d_swapchain);
+ wined3d_device_destroy_swapchain(device->wined3d_device, swapchain->wined3d_swapchain);
goto cleanup;
}
@@ -906,7 +906,7 @@ HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_devi
{
WARN("Failed to set fullscreen state, hr %#x.\n", hr);
IDXGIOutput_Release(swapchain->target);
- wined3d_swapchain_decref(swapchain->wined3d_swapchain);
+ wined3d_device_destroy_swapchain(device->wined3d_device, swapchain->wined3d_swapchain);
goto cleanup;
}
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 8405643741..f754a2bd49 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -888,6 +888,15 @@ void wined3d_device_destroy_default_samplers(struct wined3d_device *device, stru
device->null_sampler = NULL;
}
+void CDECL wined3d_device_destroy_swapchain(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
+{
+ if (device->swapchain_count && device->swapchains[0] == swapchain)
+ wined3d_device_uninit_3d(device);
+
+ wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
+ device->adapter->adapter_ops->adapter_destroy_swapchain(swapchain);
+}
+
HRESULT CDECL wined3d_device_acquire_focus_window(struct wined3d_device *device, HWND window)
{
unsigned int screensaver_active;
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 62bab65fcf..7648b99260 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -129,18 +129,9 @@ ULONG CDECL wined3d_swapchain_decref(struct wined3d_swapchain *swapchain)
if (!refcount)
{
- struct wined3d_device *device;
-
wined3d_mutex_lock();
-
- device = swapchain->device;
- if (device->swapchain_count && device->swapchains[0] == swapchain)
- wined3d_device_uninit_3d(device);
- wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
-
swapchain->parent_ops->wined3d_object_destroyed(swapchain->parent);
- swapchain->device->adapter->adapter_ops->adapter_destroy_swapchain(swapchain);
-
+ wined3d_device_destroy_swapchain(swapchain->device, swapchain);
wined3d_mutex_unlock();
}
@@ -1081,8 +1072,7 @@ HRESULT CDECL wined3d_swapchain_create(struct wined3d_device *device, struct win
wined3d_mutex_lock();
if (FAILED(hr = wined3d_device_set_implicit_swapchain(device, object)))
{
- wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
- device->adapter->adapter_ops->adapter_destroy_swapchain(object);
+ wined3d_device_destroy_swapchain(device, object);
wined3d_mutex_unlock();
return hr;
}
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index c8ef442c72..1c198c121b 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -47,6 +47,7 @@
@ cdecl wined3d_device_copy_uav_counter(ptr ptr long ptr)
@ cdecl wined3d_device_create(ptr long long ptr long long ptr long ptr ptr)
@ cdecl wined3d_device_decref(ptr)
+@ cdecl wined3d_device_destroy_swapchain(ptr ptr)
@ cdecl wined3d_device_dispatch_compute(ptr long long long)
@ cdecl wined3d_device_dispatch_compute_indirect(ptr ptr long)
@ cdecl wined3d_device_draw_indexed_primitive(ptr long long)
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index d313c7aec8..1bcae83d94 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2313,6 +2313,7 @@ HRESULT __cdecl wined3d_device_create(struct wined3d *wined3d, unsigned int adap
const enum wined3d_feature_level *feature_levels, unsigned int feature_level_count,
struct wined3d_device_parent *device_parent, struct wined3d_device **device);
ULONG __cdecl wined3d_device_decref(struct wined3d_device *device);
+void __cdecl wined3d_device_destroy_swapchain(struct wined3d_device *device, struct wined3d_swapchain *swapchain);
void __cdecl wined3d_device_dispatch_compute(struct wined3d_device *device,
unsigned int group_count_x, unsigned int group_count_y, unsigned int group_count_z);
void __cdecl wined3d_device_dispatch_compute_indirect(struct wined3d_device *device,
--
2.20.1
More information about the wine-devel
mailing list