In `generate_font_link_info`, because the return value of `GdipCreateFontFromDC` is not checked, section->font might be set to NULL. `GdipMeasureString` calls `gdip_format_string`, which then calls `generate_font_link_info` and `font_link_get_text_extent_point`. In `font_link_get_text_extent_point`, the font from `gdip_font_link_section` is also not checked for NULL, which may cause a crash.
Therefore, in `generate_font_link_info`, when `GdipCreateFontFromDC` fails, store `(GpFont *)base_font` (as with `IMLangFontLink_MapFont` failure) to ensure the font in `gdip_font_link_section` is valid.
---
This issue was reproduced while using the [QQ Music](https://y.qq.com/download/index.html). Below is the original winedbg log (on Wine 10.4 + wine-staging + DXVK, with some native libraries used. If needed and permitted by WineHQ, I will list them.) (PS: This issue should also be reproduced using generic wine master without third parties)
``` Wine-dbg>frame 1 Wine-dbg>bt Backtrace: 0 0x00000078ed4d58 get_font_hfont+0x30(graphics=<couldn't compute location>, font=<couldn't compute location>, format=<couldn't compute location>, hfont=<couldn't compute location>, lfw_return=<couldn't compute location>, matrix=<couldn't compute location>) [/home/up/wine/build32/../wine/dlls/gdiplus/graphics.c:2476] in gdiplus (0x0000000073f700) =>1 0x00000078ed21bd font_link_get_text_extent_point+0xb9(info=000000000073F774, index=0, length=0xb, max_ext=0x7fffff83, fit=000000000073F7CC, size=000000000073F7B0) [/home/up/wine/build32/../wine/dlls/gdiplus/g raphics.c:5537] in gdiplus (0x0000000073f74c) 2 0x00000078ed340d gdip_format_string+0x2f9(graphics=0000000003665DD0, hdc=0000000034010075, string=L"Q音听我想听的歌???", length=0xb, font=0000000003672700, rect=000000000073F864, format=0000000009FEB508, ignore_empt y_clip=0x1, callback=0000000078EDADC8, user_data=000000000073F878) [/home/up/wine/build32/../wine/dlls/gdiplus/graphics.c:5663] in gdiplus (0x0000000073f81c) 3 0x00000078ea8283 GdipMeasureString+0x3cb(graphics=<couldn't compute location>, string=<couldn't compute location>, length=<couldn't compute location>, font=<couldn't compute location>, rect=<couldn't compute location>, format=<couldn't compute location>, bounds=<couldn't compute location>, codepointsfitted=<couldn't compute location>, linesfilled=<couldn't compute location>) [/home/up/wine/build32/../wine/dlls/gdiplu s/graphics.c:6050] in gdiplus (0x0000000073f8c0) 4 0x00000077d41fd2 in qqmusic (+0x31fd2) (0x0000000073f908) 5 0x00000077d3e1c6 in qqmusic (+0x2e1c6) (0x0000000073f96c) 6 0x00000077d3dd11 in qqmusic (+0x2dd11) (0x0000000073f9f8) 7 0x00000077f29bd4 in qqmusic (+0x219bd4) (0x0000000073fa70) 8 0x00000077f29a63 in qqmusic (+0x219a63) (0x0000000073faa0) 9 0x00000077f28760 in qqmusic (+0x218760) (0x0000000073fb08) 10 0x00000077b059d7 in common (+0x1059d7) (0x0000000073fb94) 11 0x00000077b06c35 in common (+0x106c35) (0x0000000073fbc8) 12 0x0000007a038b48 in user32 (+0x8b48) (0x0000000073fbf8) 13 0x0000007a093e43 call_window_proc+0xa7(hwnd=0000000000060138, msg=0x113, wp=0x400, lp=0, result=000000000073FC68, arg=0000000077B06B90) [/home/up/wine/build32/../wine/dlls/user32/winproc.c:111] in user32 (0x 0000000073fc40) 14 0x0000007a09c066 dispatch_win_proc_params+0xce(params=000000000073FCA0) [/home/up/wine/build32/../wine/dlls/user32/winproc.c:710] in user32 (0x0000000073fc7c) 15 0x0000007a09be4a dispatch_message+0x9e(msg=000000000073FDCC, ansi=0) [/home/up/wine/build32/../wine/dlls/user32/message.c:804] in user32 (0x0000000073fcd8) 16 0x0000007a04f530 DispatchMessageW+0xff(msg=000000000073FDCC) [/home/up/wine/build32/../wine/dlls/user32/message.c:890] in user32 (0x0000000073fd60) 17 0x000000780c001d in qqmusic (+0x3b001d) (0x0000000073fe38) 18 0x000000780c0ce6 in qqmusic (+0x3b0ce6) (0x0000000073fea8) 19 0x00000000403af4 in qqmusic (+0x3af4) (0x0000000073fefc) 20 0x00000000403bd6 in qqmusic (+0x3bd6) (0x0000000073ff50) 21 0x0000007bcdeb10 in kernel32 (+0xeb10) (0x0000000073ff68) 22 0x0000007be0d083 in ntdll (+0xd083) (0x0000000073ff78) 23 0x0000007be435b2 call_thread_func+0x2e(entry=000000000040678E, arg=00000000003F1000) [/home/up/wine/build32/../wine/dlls/ntdll/signal_i386.c:526] in ntdll (0x0000000073ffec) Wine-dbg>info locals 0x00000078ed21bd font_link_get_text_extent_point+0xb9: (0073f74c) struct gdip_format_string_info* info=000000000073F774 (parameter [EBP+8]) INT index=0 (parameter [EBP+12]) int length=0xb (parameter [EBP+16]) int max_ext=0x7fffff83 (parameter [EBP+20]) LPINT fit=000000000073F7CC (parameter [EBP+24]) SIZE* size=000000000073F7B0 (parameter [EBP+28]) DWORD to_measure_length=0x3 (local [EBP-16]) HFONT hfont=000000000D0A00AE (local [EBP-24]) HFONT oldhfont=000000004C0A00B0 (local [EBP-20]) SIZE sizeaux={cx=0x7c, cy=0x13} (local [EBP-32]) int i=0x8 (local [EBP-8]) int fitaux=0x8 (local [EBP-36]) struct gdip_font_link_section* section=00000000037E31A8 (local [EBP-12]) Wine-dbg>p *section
Exception c0000005 Wine-dbg>x/10x 0x00000000037E31A8 0x000000037e31a8: 0073f78c 037e3188 00000008 0000000b 0x000000037e31b8: 00000000 00000000 00000004 8146001b 0x000000037e31c8: 78e0c030 78e0c030 ```
From: Eric Tian thxdaemon@gmail.com
In generate_font_link_info, because the return value of GdipCreateFontFromDC is not checked, section->font might be set to NULL. GdipMeasureString calls gdip_format_string, which then calls generate_font_link_info and font_link_get_text_extent_point. In font_link_get_text_extent_point, the font from gdip_font_link_section is also not checked for NULL, which may cause a crash.
Therefore, in generate_font_link_info, when GdipCreateFontFromDC fails, store (GpFont *)base_font (as with IMLangFontLink_MapFont failure) to ensure the font in gdip_font_link_section is valid. --- dlls/gdiplus/graphics.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index f6d79fb8356..7e23d705a38 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -5362,6 +5362,7 @@ static void generate_font_link_info(struct gdip_format_string_info *info, DWORD DWORD string_codepages; WORD *glyph_indices; HRESULT hr; + GpStatus stat;
list_init(&info->font_link_info.sections); info->font_link_info.base_font = base_font; @@ -5400,10 +5401,13 @@ static void generate_font_link_info(struct gdip_format_string_info *info, DWORD if (SUCCEEDED(hr)) { old_font = SelectObject(info->hdc, map_hfont); - GdipCreateFontFromDC(info->hdc, &gpfont); + stat = GdipCreateFontFromDC(info->hdc, &gpfont); SelectObject(info->hdc, old_font); IMLangFontLink_ReleaseFont(iMLFL, map_hfont); - section->font = gpfont; + if (stat == Ok) + section->font = gpfont; + else + section->font = (GpFont *)base_font; } else section->font = (GpFont *)base_font;
In case it's related, this is how the bug that !7149 fixed manifested.
GDI+ could fail to create a GpFont from a valid gdi32 font, if it's a bitmap font.
Ideally, we'd tell mlang not to return bitmap fonts, but I don't know if that's possible.
This merge request was approved by Esme Povirk.