[7/10] WineD3D: No bounds checking is done on sampler / texture
numbers
Stefan Dösinger
stefan at codeweavers.com
Mon Feb 19 08:24:48 CST 2007
-------------- next part --------------
From ebcca0f6339c56ebbe7b00eebf1c1cae195a96e9 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Sun, 18 Feb 2007 21:42:51 +0100
Subject: [PATCH] WineD3D: No bounds checking is done on sampler / texture numbers
Native direct3d does not check the stage / sampler number passed to
SetTexture, SetSamplerState and SetTextureStageState. This patch removes
the bounds checking and adds a test which checks that all textures
according to the hard limits mentioned in the sdk. (16 samplers in d3d9,
8 texture stages in all dx versions). I tested this on my radeon 9000
which supports up to 6 textures according to the caps.
Other investigations show that not even the hard limits are checked.
Windows happily sets sampler 16, 17, 18, ... . Around samler 40
applications begin to crash randomly, so setting invalid samplers seems
to cause memory corruption. A test for that is NOT included because it
could crash or leave the device in an unpredictable state
---
dlls/d3d8/tests/device.c | 59 ++++++++++++++++++++++++++++++++++++++++++
dlls/d3d9/tests/device.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/d3d.c | 30 +++++++++++++++++++++
dlls/wined3d/device.c | 24 -----------------
4 files changed, 153 insertions(+), 24 deletions(-)
diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c
index 76a6b8b..c4f65d6 100644
--- a/dlls/d3d8/tests/device.c
+++ b/dlls/d3d8/tests/device.c
@@ -942,6 +942,64 @@ cleanup:
if(hwnd) DestroyWindow(hwnd);
}
+static void test_limits(void)
+{
+ HRESULT hr;
+ HWND hwnd = NULL;
+ IDirect3D8 *pD3d = NULL;
+ IDirect3DDevice8 *pDevice = NULL;
+ D3DPRESENT_PARAMETERS d3dpp;
+ D3DDISPLAYMODE d3ddm;
+ IDirect3DTexture8 *pTexture = NULL;
+ int i;
+
+ pD3d = pDirect3DCreate8( D3D_SDK_VERSION );
+ ok(pD3d != NULL, "Failed to create IDirect3D8 object\n");
+ hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
+ ok(hwnd != NULL, "Failed to create window\n");
+ if (!pD3d || !hwnd) goto cleanup;
+
+ IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
+ ZeroMemory( &d3dpp, sizeof(d3dpp) );
+ d3dpp.Windowed = TRUE;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.BackBufferWidth = 800;
+ d3dpp.BackBufferHeight = 600;
+ d3dpp.BackBufferFormat = d3ddm.Format;
+ d3dpp.EnableAutoDepthStencil = TRUE;
+ d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
+
+ hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
+ ok(hr == D3D_OK, "IDirect3D8_CreateDevice failed with %s\n", DXGetErrorString8(hr));
+ if(!pDevice) goto cleanup;
+
+ hr = IDirect3DDevice8_CreateTexture(pDevice, 16, 16, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture);
+ ok(hr == D3D_OK, "IDirect3DDevice8_CreateTexture failed with %s\n", DXGetErrorString8(hr));
+ if(!pTexture) goto cleanup;
+
+ /* There are 8 texture stages. We should be able to access all of them */
+ for(i = 0; i < 8; i++) {
+ hr = IDirect3DDevice8_SetTexture(pDevice, i, (IDirect3DBaseTexture8 *) pTexture);
+ ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %s\n", i, DXGetErrorString8(hr));
+ hr = IDirect3DDevice8_SetTexture(pDevice, i, NULL);
+ ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %s\n", i, DXGetErrorString8(hr));
+ hr = IDirect3DDevice8_SetTextureStageState(pDevice, i, D3DTSS_COLOROP, D3DTOP_ADD);
+ ok(hr == D3D_OK, "IDirect3DDevice8_SetTextureStageState for texture %d failed with %s\n", i, DXGetErrorString8(hr));
+ }
+
+ /* Investigations show that accessing higher textures stage states does not return an error either. Writing
+ * to too high texture stages(approximately texture 40) causes memory corruption in windows, so there is no
+ * bounds checking but how do I test that?
+ */
+
+cleanup:
+ if(pTexture) IDirect3DTexture8_Release(pTexture);
+ if(pD3d) IDirect3D8_Release(pD3d);
+ if(pDevice) IDirect3D8_Release(pDevice);
+ if(hwnd) DestroyWindow(hwnd);
+}
+
START_TEST(device)
{
HMODULE d3d8_handle = LoadLibraryA( "d3d8.dll" );
@@ -964,5 +1022,6 @@ START_TEST(device)
test_states();
test_scene();
test_shader();
+ test_limits();
}
}
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 2e923b8..19862db 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -1094,6 +1094,69 @@ cleanup:
if(hwnd) DestroyWindow(hwnd);
}
+static void test_limits(void)
+{
+ HRESULT hr;
+ HWND hwnd = NULL;
+ IDirect3D9 *pD3d = NULL;
+ IDirect3DDevice9 *pDevice = NULL;
+ D3DPRESENT_PARAMETERS d3dpp;
+ D3DDISPLAYMODE d3ddm;
+ IDirect3DTexture9 *pTexture = NULL;
+ int i;
+
+ pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
+ ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
+ hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
+ ok(hwnd != NULL, "Failed to create window\n");
+ if (!pD3d || !hwnd) goto cleanup;
+
+ IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
+ ZeroMemory( &d3dpp, sizeof(d3dpp) );
+ d3dpp.Windowed = TRUE;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.BackBufferWidth = 800;
+ d3dpp.BackBufferHeight = 600;
+ d3dpp.BackBufferFormat = d3ddm.Format;
+ d3dpp.EnableAutoDepthStencil = TRUE;
+ d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
+
+ hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
+ ok(hr == D3D_OK, "IDirect3D9_CreateDevice failed with %s\n", DXGetErrorString9(hr));
+ if(!pDevice) goto cleanup;
+
+ hr = IDirect3DDevice9_CreateTexture(pDevice, 16, 16, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture, NULL);
+ ok(hr == D3D_OK, "IDirect3DDevice9_CreateTexture failed with %s\n", DXGetErrorString9(hr));
+ if(!pTexture) goto cleanup;
+
+ /* There are 16 pixel samplers. We should be able to access all of them */
+ for(i = 0; i < 16; i++) {
+ hr = IDirect3DDevice9_SetTexture(pDevice, i, (IDirect3DBaseTexture9 *) pTexture);
+ ok(hr == D3D_OK, "IDirect3DDevice9_SetTexture for sampler %d failed with %s\n", i, DXGetErrorString9(hr));
+ hr = IDirect3DDevice9_SetTexture(pDevice, i, NULL);
+ ok(hr == D3D_OK, "IDirect3DDevice9_SetTexture for sampler %d failed with %s\n", i, DXGetErrorString9(hr));
+ hr = IDirect3DDevice9_SetSamplerState(pDevice, i, D3DSAMP_SRGBTEXTURE, TRUE);
+ ok(hr == D3D_OK, "IDirect3DDevice9_SetSamplerState for sampler %d failed with %s\n", i, DXGetErrorString9(hr));
+ }
+
+ /* Now test all 8 textures stage states */
+ for(i = 0; i < 8; i++) {
+ hr = IDirect3DDevice9_SetTextureStageState(pDevice, i, D3DTSS_COLOROP, D3DTOP_ADD);
+ ok(hr == D3D_OK, "IDirect3DDevice9_SetTextureStageState for texture %d failed with %s\n", i, DXGetErrorString9(hr));
+ }
+
+ /* Investigations show that accessing higher samplers / textures stage states does not return an error either. Writing
+ * to too high samplers(approximately sampler 40) causes memory corruption in windows, so there is no bounds checking
+ * but how do I test that?
+ */
+cleanup:
+ if(pTexture) IDirect3DTexture9_Release(pTexture);
+ if(pD3d) IDirect3D9_Release(pD3d);
+ if(pDevice) IDirect3D9_Release(pDevice);
+ if(hwnd) DestroyWindow(hwnd);
+}
+
START_TEST(device)
{
HMODULE d3d9_handle = LoadLibraryA( "d3d9.dll" );
@@ -1114,5 +1177,6 @@ START_TEST(device)
test_cursor();
test_reset();
test_scene();
+ test_limits();
}
}
diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c
index 29d0b0c..bb37f08 100644
--- a/dlls/ddraw/tests/d3d.c
+++ b/dlls/ddraw/tests/d3d.c
@@ -521,6 +521,35 @@ static void SceneTest(void)
/* TODO: Verify that blitting works in the same way as in d3d9 */
}
+static void LimitTest(void)
+{
+ IDirectDrawSurface7 *pTexture = NULL;
+ HRESULT hr;
+ int i;
+ DDSURFACEDESC2 ddsd;
+
+ memset(&ddsd, 0, sizeof(ddsd));
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+ ddsd.dwWidth = 16;
+ ddsd.dwHeight = 16;
+ hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &pTexture, NULL);
+ ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
+ if(!pTexture) return;
+
+ for(i = 0; i < 8; i++) {
+ hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, pTexture);
+ ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
+ hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, NULL);
+ ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
+ hr = IDirect3DDevice7_SetTextureStageState(lpD3DDevice, i, D3DTSS_COLOROP, D3DTOP_ADD);
+ ok(hr == D3D_OK, "IDirect3DDevice8_SetTextureStageState for texture %d failed with %08x\n", i, hr);
+ }
+
+ IDirectDrawSurface7_Release(pTexture);
+}
+
START_TEST(d3d)
{
init_function_pointers();
@@ -537,5 +566,6 @@ START_TEST(d3d)
ProcessVerticesTest();
StateTest();
SceneTest();
+ LimitTest();
ReleaseDirect3D();
}
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 333e79b..9bd248f 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -2695,12 +2695,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface,
* GL_MAX_TEXTURE_COORDS_ARB.
* Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
******************/
- /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
- if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
- FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
- Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
- return WINED3DERR_INVALIDCALL;
- }
TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
debug_d3dsamplerstate(Type), Type, Value);
@@ -2726,7 +2720,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface,
static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
- /** TODO: check that sampler is in range **/
*Value = This->stateBlock->samplerState[Sampler][Type];
TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
@@ -3685,12 +3678,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *if
TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
- /* Reject invalid texture units */
- if (Stage >= GL_LIMITS(texture_stages)) {
- TRACE("Attempt to access invalid texture rejected\n");
- return WINED3DERR_INVALIDCALL;
- }
-
This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
This->updateStateBlock->textureState[Stage][Type] = Value;
@@ -3789,12 +3776,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD
}
#endif
- /* Reject invalid texture units */
- if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
- WARN("Attempt to access invalid texture rejected\n");
- return WINED3DERR_INVALIDCALL;
- }
-
if(pTexture != NULL) {
/* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
*/
@@ -3888,11 +3869,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
- /* Reject invalid texture units */
- if (Stage >= GL_LIMITS(sampler_stages)) {
- TRACE("Attempt to access invalid texture rejected\n");
- return WINED3DERR_INVALIDCALL;
- }
*ppTexture=This->stateBlock->textures[Stage];
if (*ppTexture)
IWineD3DBaseTexture_AddRef(*ppTexture);
--
1.4.4.3
More information about the wine-patches
mailing list