Downgrade C++11 to C++98 calls.
Use Fl_String instead of std::string.Windows: fix "heap-use-after-free" in home_directory_name()
Calling getenv() twice with different output vars and accessing both
later could cause "heap-use-after-free" error in some Windows versions.
The result of home_directory_name() would be unpredictable.
Found using Wine and/or MSYS2/clang/libc++ with Address Sanitizer.
(cherry picked from commit 719fed2b13)
This commit is contained in:
parent
5e82d0ba78
commit
2e47aeb384
@ -1,7 +1,7 @@
|
||||
//
|
||||
// Definition of Windows system driver for the Fast Light Tool Kit (FLTK).
|
||||
//
|
||||
// Copyright 1998-2023 by Bill Spitzak and others.
|
||||
// Copyright 1998-2025 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
@ -19,10 +19,10 @@
|
||||
#include "Fl_WinAPI_System_Driver.H"
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/fl_utf8.h>
|
||||
#include <FL/fl_string_functions.h> // fl_strdup()
|
||||
#include <FL/filename.H>
|
||||
#include <FL/Fl_File_Browser.H>
|
||||
#include <FL/Fl_File_Icon.H>
|
||||
#include "../../Fl_String.H"
|
||||
#include "../../flstring.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
@ -64,6 +64,18 @@ typedef RPC_STATUS (WINAPI *uuid_func)(UUID __RPC_FAR *Uuid);
|
||||
# include <mntent.h>
|
||||
#endif
|
||||
|
||||
// Optional helper function to debug Fl_WinAPI_System_Driver::home_directory_name()
|
||||
#ifndef DEBUG_HOME_DIRECTORY_NAME
|
||||
#define DEBUG_HOME_DIRECTORY_NAME 0
|
||||
#endif
|
||||
#if DEBUG_HOME_DIRECTORY_NAME
|
||||
static void print_env(const char *ev) {
|
||||
const char *val = getenv(ev);
|
||||
printf("%-30.30s = \"%s\"\n", ev, val ? val : "<null>");
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif // DEBUG_HOME_DIRECTORY_NAME
|
||||
|
||||
static inline int isdirsep(char c) { return c == '/' || c == '\\'; }
|
||||
|
||||
static wchar_t *mbwbuf = NULL;
|
||||
@ -985,41 +997,64 @@ int Fl_WinAPI_System_Driver::file_type(const char *filename)
|
||||
return filetype;
|
||||
}
|
||||
|
||||
// Note: the result is cached in a static variable
|
||||
const char *Fl_WinAPI_System_Driver::home_directory_name()
|
||||
{
|
||||
static char *home = NULL;
|
||||
if (home)
|
||||
return home;
|
||||
// Various ways to retrieve the HOME path.
|
||||
if (!home) {
|
||||
static Fl_String home;
|
||||
if (!home.empty())
|
||||
return home.c_str();
|
||||
|
||||
#if (DEBUG_HOME_DIRECTORY_NAME)
|
||||
print_env("HOMEDRIVE");
|
||||
print_env("HOMEPATH");
|
||||
print_env("UserProfile");
|
||||
print_env("HOME");
|
||||
#endif
|
||||
|
||||
// Implement various ways to retrieve the HOME path.
|
||||
// Note, from `man getenv`:
|
||||
// "The implementation of getenv() is not required to be reentrant.
|
||||
// The string pointed to by the return value of getenv() may be statically
|
||||
// allocated, and can be modified by a subsequent call to getenv()...".
|
||||
// Tests show that this is the case in some MinGW implementations.
|
||||
|
||||
if (home.empty()) {
|
||||
const char *home_drive = getenv("HOMEDRIVE");
|
||||
const char *home_path = getenv("HOMEPATH");
|
||||
if (home_path && home_drive) {
|
||||
int n = strlen(home_drive) + strlen(home_path) + 2;
|
||||
home = (char *)::malloc(n);
|
||||
::strncpy(home, home_drive, n);
|
||||
::strncat(home, home_path, n);
|
||||
}
|
||||
}
|
||||
if (!home) {
|
||||
if (home_drive) {
|
||||
home = home_drive; // copy *before* calling getenv() again, see above
|
||||
const char *home_path = getenv("HOMEPATH");
|
||||
if (home_path) {
|
||||
home.append(home_path);
|
||||
} else {
|
||||
home.clear(); // reset
|
||||
} // home_path
|
||||
} // home_drive
|
||||
} // empty()
|
||||
|
||||
if (home.empty()) {
|
||||
const char *h = getenv("UserProfile");
|
||||
if (h)
|
||||
home = ::strdup(h);
|
||||
home = h;
|
||||
}
|
||||
if (!home) {
|
||||
|
||||
if (home.empty()) {
|
||||
const char *h = getenv("HOME");
|
||||
if (h)
|
||||
home = ::strdup(h);
|
||||
home = h;
|
||||
}
|
||||
if (!home) {
|
||||
home = ::strdup("~/"); // last resort
|
||||
if (home.empty()) {
|
||||
home = "~/"; // last resort
|
||||
}
|
||||
// Make path canonical.
|
||||
for (char *s = home; *s; s++) {
|
||||
if (*s == '\\')
|
||||
*s = '/';
|
||||
for (int i = 0; i < home.size(); ++i) {
|
||||
if (home[i] == '\\')
|
||||
home[i] = '/';
|
||||
}
|
||||
return home;
|
||||
#if (DEBUG_HOME_DIRECTORY_NAME)
|
||||
printf("home_directory_name() returns \"%s\"\n", home.c_str());
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return home.c_str();
|
||||
}
|
||||
|
||||
void Fl_WinAPI_System_Driver::gettime(time_t *sec, int *usec) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user