diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c index d53b8f2..4149263 100644 --- a/dlls/gdi32/dib.c +++ b/dlls/gdi32/dib.c @@ -189,9 +189,24 @@ INT WINAPI StretchDIBits(HDC hdc, INT xDst, INT yDst, INT widthDst, const BITMAPINFO *info, UINT wUsage, DWORD dwRop ) { DC *dc; + int nsrcbytes; + /* Many broken apps pass bad pointers to this function; see bug 7380. + * Windows catches this and returns silently, in spite of + * what TheOldNewThing says about crashing being better. + */ if (!bits || !info) return 0; + if (info->bmiHeader.biCompression) + nsrcbytes = 1; /* checking start better than nothing */ + else { + int dibpitch = ((widthSrc * info->bmiHeader.biBitCount + 31) &~31) / 8; + nsrcbytes = heightSrc * dibpitch; + if (nsrcbytes < 0) + nsrcbytes = - nsrcbytes; + } + if (IsBadReadPtr(bits, nsrcbytes)) /* so shoot me */ + return 0; if (!(dc = get_dc_ptr( hdc ))) return FALSE; @@ -378,8 +393,24 @@ INT WINAPI SetDIBitsToDevice(HDC hdc, INT xDest, INT yDest, DWORD cx, { INT ret; DC *dc; + int nsrcbytes; - if (!bits) return 0; + /* Many broken apps pass bad pointers to this function; see bug 7380. + * Windows catches this and returns silently, in spite of + * what TheOldNewThing says about crashing being better. + */ + if (!bits || !info) + return 0; + if (info->bmiHeader.biCompression) + nsrcbytes = 1; /* checking start better than nothing */ + else { + int dibpitch = ((cx * info->bmiHeader.biBitCount + 31) &~31) / 8; + nsrcbytes = cy * dibpitch; + if (nsrcbytes < 0) + nsrcbytes = - nsrcbytes; + } + if (IsBadReadPtr(bits, nsrcbytes)) /* so shoot me */ + return 0; if (!(dc = get_dc_ptr( hdc ))) return 0; diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c index c31d367..82ac935 100644 --- a/dlls/gdi32/tests/bitmap.c +++ b/dlls/gdi32/tests/bitmap.c @@ -1147,10 +1147,12 @@ static void test_GetDIBits_selected_DIB(UINT bpp) ok(equalContents, "GetDIBits with DIB selected in DC: Invalid DIB color table\n"); equalContents = TRUE; + trace("checking %d bytes\n", dib_size); for (i=0; i < dib_size / sizeof(DWORD); i++) { if (((DWORD *)bits)[i] != ((DWORD *)bits2)[i]) { + trace("bits[%d] %x != bits2[%d] %x \n", i, ((DWORD *)bits)[i], i, ((DWORD *)bits2)[i]); equalContents = FALSE; break; } @@ -2017,6 +2019,60 @@ void test_GdiAlphaBlend() } +static void test_badbits() +{ + char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)]; + BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf; + HDC hdc0, hdc; + int ret; + void *bits; + DWORD oldprotect; + SYSTEM_INFO si; + + memset(pbmi, 0, sizeof(bmibuf)); + pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader); + pbmi->bmiHeader.biHeight = 100; + pbmi->bmiHeader.biWidth = 100; + pbmi->bmiHeader.biBitCount = 24; + pbmi->bmiHeader.biPlanes = 1; + pbmi->bmiHeader.biCompression = BI_RGB; + hdc0 = GetDC(0); + hdc = CreateCompatibleDC( hdc0); + + GetSystemInfo( &si); + bits = VirtualAlloc( NULL, 40000, MEM_COMMIT, PAGE_READONLY); + ok( (int)bits, "VirtualAlloc failed\n"); + + /* source bits can be read, StretchDIBits succeeds */ + ret = StretchDIBits( hdc, 0, 0, 100, 100, 0, 0, 100, 100, bits, + pbmi, 0, SRCCOPY); + ok( ret, "StretchDIBits failed\n"); + + ret = VirtualProtect( (char*)bits + si.dwPageSize, si.dwPageSize, + PAGE_NOACCESS, &oldprotect); + ok( ret, "VirtualProtect failed\n"); + /* source bits cannot all be read, StretchDIBits fails */ + /* and should not crash */ + ret = StretchDIBits( hdc, 0, 0, 100, 100, 0, 0, 100, 100, bits, + pbmi, 0, SRCCOPY); + ok( !ret, "StretchDIBits should have failed\n"); + + /* same tests for SetDIBitsToDevice */ + ret = SetDIBitsToDevice( hdc, 0, 0, 100, 100, 0, 0, 0, 100, bits, + pbmi, DIB_RGB_COLORS); + ok( !ret, "SetDIBitsToDevice should have failed\n"); + + ret = VirtualProtect( (char*)bits + si.dwPageSize, si.dwPageSize, + PAGE_READONLY, &oldprotect); + ok( ret, "VirtualProtect failed\n"); + ret = SetDIBitsToDevice( hdc, 0, 0, 100, 100, 0, 0, 0, 100, bits, + pbmi, DIB_RGB_COLORS); + ok( ret, "SetDIBitsToDevice should have succeeded\n"); + + DeleteDC( hdc); + ReleaseDC(0, hdc0); +} + START_TEST(bitmap) { HMODULE hdll; @@ -2041,4 +2097,5 @@ START_TEST(bitmap) test_GdiAlphaBlend(); test_bitmapinfoheadersize(); test_get16dibits(); + test_badbits(); }