Skip to content

Commit 6f8c80b

Browse files
authored
Merge pull request #46 from zao/fix/bad-userpath
fix: harden UserPath against unusable folders
2 parents 23a0c59 + ea4ee20 commit 6f8c80b

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)