From 81557b5e21551150296b811f7617bca4a75a0c70 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Mon, 2 Aug 2010 15:35:04 +0900 Subject: [PATCH] gdi32: Do not crash on an invalid pointer passed to AddFontMemResourceEx. --- dlls/gdi32/font.c | 21 ++++++++++- dlls/gdi32/freetype.c | 2 +- dlls/gdi32/tests/font.c | 83 +++++++++++++++++++++++++++++++++++++++++ include/wingdi.h | 1 + 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 29281f9b04e..9ebf7b37d9e 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -33,6 +33,7 @@ #include "winnls.h" #include "wownt32.h" #include "gdi_private.h" +#include "wine/exception.h" #include "wine/unicode.h" #include "wine/debug.h" @@ -3184,7 +3185,25 @@ BOOL WINAPI RemoveFontResourceW( LPCWSTR str ) */ HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts) { - return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts); + HANDLE ret; + DWORD num_fonts; + + ret = WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, &num_fonts); + if (ret) + { + __TRY + { + *pcFonts = num_fonts; + } + __EXCEPT_PAGE_FAULT + { + WARN("page fault while writing to *pcFonts (%p)\n", pcFonts); + RemoveFontMemResourceEx(ret); + ret = 0; + } + __ENDTRY + } + return ret; } /*********************************************************************** diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 532278c4107..e2db1aa7be4 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -2151,7 +2151,7 @@ HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD { TRACE("AddFontToList failed\n"); HeapFree(GetProcessHeap(), 0, pFontCopy); - return NULL; + return 0; } /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle? * For now return something unique but quite random diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index d89132db441..bbb54cd44fd 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -44,6 +44,8 @@ DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags); BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *); HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *); +HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *); +BOOL (WINAPI *pRemoveFontMemResourceEx)(HANDLE); static HMODULE hgdi32 = 0; @@ -59,6 +61,8 @@ static void init(void) pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW"); pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo"); pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA"); + pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx"); + pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx"); } static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam) @@ -3142,6 +3146,84 @@ static void test_CreateFontIndirectEx(void) DeleteObject(hfont); } +static void free_font(void *font) +{ + UnmapViewOfFile(font); +} + +static void *load_font(const char *font_name, DWORD *font_size) +{ + char file_name[MAX_PATH]; + HANDLE file, mapping; + void *font; + + if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL; + strcat(file_name, "\\fonts\\"); + strcat(file_name, font_name); + + file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + if (file == INVALID_HANDLE_VALUE) return NULL; + + *font_size = GetFileSize(file, NULL); + + mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mapping) + { + CloseHandle(file); + return NULL; + } + + font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); + + CloseHandle(file); + CloseHandle(mapping); + return font; +} + +static void test_AddFontMemResource(void) +{ + void *font; + DWORD font_size, num_fonts; + HANDLE ret; + + if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx) + { + win_skip("AddFontMemResourceEx is not available on this platform\n"); + return; + } + + font = load_font("sserife.fon", &font_size); + if (!font) + { + skip("Unable to locate and load font sserife.fon\n"); + return; + } + + num_fonts = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts); + ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError()); + ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n"); + ok(num_fonts != 0, "number of loaded fonts should not be 0\n"); + + free_font(font); + + SetLastError(0xdeadbeef); + ok(pRemoveFontMemResourceEx(ret), "RemoveFontMemResourceEx error %d\n", GetLastError()); + + /* test invalid pointer to number of loaded fonts */ + font = load_font("sserife.fon", &font_size); + ok(font != NULL, "Unable to locate and load font sserife.fon\n"); + + ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef); + ok(!ret, "AddFontMemResourceEx should fail\n"); + + ret = pAddFontMemResourceEx(font, font_size, NULL, NULL); + ok(!ret, "AddFontMemResourceEx should fail\n"); + + free_font(font); +} + START_TEST(font) { init(); @@ -3162,6 +3244,7 @@ START_TEST(font) test_nonexistent_font(); test_orientation(); test_height_selection(); + test_AddFontMemResource(); /* On Windows Arial has a lot of default charset aliases such as Arial Cyr, * I'd like to avoid them in this test. diff --git a/include/wingdi.h b/include/wingdi.h index 3f5058fdfbc..fa68c230bdc 100644 --- a/include/wingdi.h +++ b/include/wingdi.h @@ -3630,6 +3630,7 @@ WINGDIAPI UINT WINAPI RealizePalette(HDC); WINGDIAPI BOOL WINAPI Rectangle(HDC,INT,INT,INT,INT); WINGDIAPI BOOL WINAPI RectInRegion(HRGN,const RECT *); WINGDIAPI BOOL WINAPI RectVisible(HDC,const RECT*); +WINGDIAPI BOOL WINAPI RemoveFontMemResourceEx(HANDLE); WINGDIAPI BOOL WINAPI RemoveFontResourceA(LPCSTR); WINGDIAPI BOOL WINAPI RemoveFontResourceW(LPCWSTR); #define RemoveFontResource WINELIB_NAME_AW(RemoveFontResource)