diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2025-03-15 21:22:21 +0100 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2025-03-15 21:22:21 +0100 |
| commit | 2e1730d2f0f131d792c9b0561672f5252a868785 (patch) | |
| tree | 93feaa2dc3d980a8a09242f630b388bcc35142ee /src | |
| parent | 24aec69f27aedeead49ed629b7d434b8846826d3 (diff) | |
Fix potential buffer overflow on Windows when loading fonts (#1221)
This commit is bigger than necessary to fix the buffer allocation but
it also prevents some unnecessary string copies: the font name is
converted from UTF-16 to UTF-8 directly in the buffer used later.
Code reformatted and clarified as well, some duplicated code was
removed.
Diffstat (limited to 'src')
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx index f350dcd40..f3fac4cfb 100644 --- a/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx +++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx @@ -84,30 +84,47 @@ const char* Fl_GDI_Graphics_Driver::get_font_name(Fl_Font fnum, int* ap) { static int fl_free_font = FL_FREE_FONT; +// helper function for `enumcbw()` to avoid code repetition +// input: +// ft: font "type", i.e. ' ', 'B', 'I', or 'P' +// fn: font name whose first byte is overwritten and then stored + +static void set_font_name(const char ft, char *fn) { + fn[0] = ft; + Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(fn)); +} + +// Callback for EnumFontFamiliesW(): +// return 1 to continue, 0 to stop enumeration + static int CALLBACK enumcbw(CONST LOGFONTW *lpelf, - CONST TEXTMETRICW * /*lpntm*/, - DWORD /*FontType*/, - LPARAM p) { + CONST TEXTMETRICW * /* lpntm */, + DWORD /* FontType */, + LPARAM p) { if (!p && lpelf->lfCharSet != ANSI_CHARSET) return 1; - char *n = NULL; - size_t l = wcslen(lpelf->lfFaceName); - unsigned dstlen = fl_utf8fromwc(n, 0, (wchar_t*)lpelf->lfFaceName, (unsigned) l) + 1; // measure the string - n = (char*) malloc(dstlen); -//n[fl_unicode2utf((wchar_t*)lpelf->lfFaceName, l, n)] = 0; - dstlen = fl_utf8fromwc(n, dstlen, (wchar_t*)lpelf->lfFaceName, (unsigned) l); // convert the string - n[dstlen] = 0; - for (int i=0; i<FL_FREE_FONT; i++) // skip if one of our built-in fonts - if (!strcmp(Fl::get_font_name((Fl_Font)i),n)) {free(n);return 1;} - char buffer[LF_FACESIZE + 1]; - strcpy(buffer+1, n); - buffer[0] = ' '; Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer)); + char *fn = nullptr; // FLTK font name + unsigned lw = (unsigned)wcslen(lpelf->lfFaceName); + unsigned dstlen = fl_utf8fromwc(fn, 0, (wchar_t*)lpelf->lfFaceName, lw); // measure the string + fn = (char*)malloc((size_t)dstlen + 2); // "?" + name + NUL + if (!fn) return 1; + fn[0] = ' '; + dstlen = fl_utf8fromwc(fn+1, dstlen+1, (wchar_t*)lpelf->lfFaceName, lw); // convert the string + fn[dstlen] = 0; + // skip if it is one of our built-in fonts + for (int i = 0; i < FL_FREE_FONT; i++) { + if (!strcmp(Fl::get_font_name((Fl_Font)i), fn+1)) { + free(fn); + return 1; + } + } + set_font_name(' ', fn); if (lpelf->lfWeight <= 400) - buffer[0] = 'B', Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer)); - buffer[0] = 'I'; Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer)); + set_font_name('B', fn); + set_font_name('I', fn); if (lpelf->lfWeight <= 400) - buffer[0] = 'P', Fl::set_font((Fl_Font)(fl_free_font++), fl_strdup(buffer)); - free(n); + set_font_name('P', fn); + free(fn); return 1; } /* enumcbw */ @@ -129,9 +146,9 @@ static int sizes[128]; static int CALLBACK EnumSizeCbW(CONST LOGFONTW * /*lpelf*/, - CONST TEXTMETRICW *lpntm, - DWORD fontType, - LPARAM /*p*/) { + CONST TEXTMETRICW *lpntm, + DWORD fontType, + LPARAM /*p*/) { if ((fontType & RASTER_FONTTYPE) == 0) { sizes[0] = 0; nbSize = 1; |
