summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlbrecht Schlosser <albrechts.fltk@online.de>2025-03-15 21:22:21 +0100
committerAlbrecht Schlosser <albrechts.fltk@online.de>2025-03-15 21:22:21 +0100
commit2e1730d2f0f131d792c9b0561672f5252a868785 (patch)
tree93feaa2dc3d980a8a09242f630b388bcc35142ee
parent24aec69f27aedeead49ed629b7d434b8846826d3 (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.
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_font.cxx61
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;