[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