Skip to content

Commit ea4ee20

Browse files
committed
fix: harden UserPath against unusable folders
The user path location may both be inaccessible thanks to malfunctioning cloud providers and due to not being representable in the user codepage that is needed for interacting with the file system in a narrow way in Lua. If an error occurs, the Lua function returns nil and an approximation in the user codepage of the path, suitable for use in an error message.
1 parent 23a0c59 commit ea4ee20

3 files changed

Lines changed: 52 additions & 11 deletions

File tree

engine/system/sys_main.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ class sys_IMain {
6464
bool debug = false;
6565
bool debuggerRunning = false;
6666
int processorCount = 0;
67-
std::string basePath;
68-
std::string userPath;
67+
std::string basePath;
68+
std::optional<std::string> userPath;
69+
std::optional<std::string> invalidUserPath;
6970

7071
virtual int GetTime() = 0;
7172
virtual void Sleep(int msec) = 0;

engine/system/win/sys_main.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -712,14 +712,44 @@ std::string FindBasePath()
712712
#endif
713713
}
714714

715-
std::string FindUserPath()
715+
std::optional<std::string> FindUserPath(std::optional<std::string>& invalidPath)
716716
{
717717
#ifdef _WIN32
718-
PWSTR os_path{};
719-
SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &os_path);
720-
std::filesystem::path path(os_path);
721-
CoTaskMemFree(os_path);
722-
return path.string();
718+
PWSTR osPath{};
719+
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &osPath);
720+
if (FAILED(hr)) {
721+
// The path may be inaccessible due to malfunctioning cloud providers.
722+
CoTaskMemFree(osPath);
723+
invalidPath.reset();
724+
return {};
725+
}
726+
std::wstring pathStr = osPath;
727+
CoTaskMemFree(osPath);
728+
std::filesystem::path path(pathStr);
729+
try {
730+
return path.string();
731+
}
732+
catch (std::system_error) {
733+
// The path could not be converted into the narrow representation, convert the path
734+
// string lossily for use in an ASCII error message on the Lua side.
735+
invalidPath.reset();
736+
std::wstring pathStr = path.wstring();
737+
char defGlyph = '?';
738+
BOOL defGlyphUsed{};
739+
DWORD convFlags = WC_COMPOSITECHECK | WC_NO_BEST_FIT_CHARS | WC_DEFAULTCHAR;
740+
int cb = WideCharToMultiByte(CP_ACP, 0, pathStr.c_str(), -1, nullptr, 0, &defGlyph, &defGlyphUsed);
741+
if (cb) {
742+
std::vector<char> buf(cb);
743+
WideCharToMultiByte(CP_ACP, 0, pathStr.c_str(), -1, buf.data(), cb, &defGlyph, &defGlyphUsed);
744+
for (auto& ch : buf) {
745+
if ((unsigned char)ch >= 0x80) {
746+
ch = '?'; // Substitute characters that we can represent but can't draw.
747+
}
748+
}
749+
invalidPath = buf.data();
750+
}
751+
return {};
752+
}
723753
#else
724754
if (char const* data_home_path = getenv("XDG_DATA_HOME")) {
725755
return data_home_path;
@@ -755,7 +785,7 @@ sys_main_c::sys_main_c()
755785

756786
// Set the local system information
757787
basePath = FindBasePath();
758-
userPath = FindUserPath();
788+
userPath = FindUserPath(invalidUserPath);
759789
}
760790

761791
bool sys_main_c::Run(int argc, char** argv)

ui_api.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
** msec = GetTime()
6868
** path = GetScriptPath()
6969
** path = GetRuntimePath()
70-
** path = GetUserPath()
70+
** path, missingPath = GetUserPath() -- may fail, then returns nil and and approximation of the bad path
7171
** SetWorkDir("<path>")
7272
** path = GetWorkDir()
7373
** ssID = LaunchSubScript("<scriptText>", "<funcList>", "<subList>"[, ...])
@@ -1065,7 +1065,17 @@ static int l_GetRuntimePath(lua_State* L)
10651065
static int l_GetUserPath(lua_State* L)
10661066
{
10671067
ui_main_c* ui = GetUIPtr(L);
1068-
lua_pushstring(L, ui->sys->userPath.c_str());
1068+
auto& userPath = ui->sys->userPath;
1069+
if (userPath) {
1070+
lua_pushstring(L, userPath->c_str());
1071+
return 1;
1072+
}
1073+
1074+
lua_pushnil(L);
1075+
if (auto& invalidUserPath = ui->sys->invalidUserPath) {
1076+
lua_pushstring(L, invalidUserPath->c_str());
1077+
return 2;
1078+
}
10691079
return 1;
10701080
}
10711081

0 commit comments

Comments
 (0)