diff --git a/source/lib/status.cpp b/source/lib/status.cpp index 88a94dcad6..a967868b42 100644 --- a/source/lib/status.cpp +++ b/source/lib/status.cpp @@ -130,6 +130,7 @@ STATUS_DEFINE(ERR, TIMED_OUT, L"Timed out", -1); STATUS_DEFINE(ERR, REENTERED, L"Single-call function was reentered", -1); STATUS_DEFINE(ERR, CORRUPTED, L"File/memory data is corrupted", -1); STATUS_DEFINE(ERR, VERSION, L"Version mismatch", -1); +STATUS_DEFINE(ERR, ABORTED, L"Operation aborted", -1); STATUS_DEFINE(ERR, INVALID_PARAM, L"Invalid function argument", EINVAL); STATUS_DEFINE(ERR, INVALID_HANDLE, L"Invalid Handle (argument)", -1); diff --git a/source/lib/status.h b/source/lib/status.h index 9ef5461dbd..12967af031 100644 --- a/source/lib/status.h +++ b/source/lib/status.h @@ -251,7 +251,7 @@ extern Status StatusFromErrno(); {\ const Status status_ = (expression);\ if(status_ < 0)\ - DEBUG_WARN_ERR(status_);\ + DEBUG_WARN_ERR(status_);\ }\ while(0) @@ -375,6 +375,7 @@ namespace ERR const Status REENTERED = -100012; const Status CORRUPTED = -100013; const Status VERSION = -100014; + const Status ABORTED = -100015; // function arguments const Status INVALID_PARAM = -100020; diff --git a/source/lib/sysdep/os/win/mahaf.cpp b/source/lib/sysdep/os/win/mahaf.cpp index 42550875d1..d56e6232d4 100644 --- a/source/lib/sysdep/os/win/mahaf.cpp +++ b/source/lib/sysdep/os/win/mahaf.cpp @@ -251,7 +251,11 @@ static void StartDriver(const OsPath& driverPathname) { const SC_HANDLE hSCM = OpenServiceControlManager(); if(!hSCM) + { + ENSURE(GetLastError() == ERROR_ACCESS_DENIED); + SetLastError(0); return; + } SC_HANDLE hService = OpenServiceW(hSCM, AKEN_NAME, SERVICE_ALL_ACCESS); @@ -328,6 +332,8 @@ static OsPath DriverPathname() static Status Init() { + WinScopedPreserveLastError s; + if(wutil_HasCommandLineArgument(L"-wNoMahaf")) return ERR::NOT_SUPPORTED; // NOWARN @@ -340,7 +346,11 @@ static Status Init() const DWORD shareMode = 0; hAken = CreateFileW(L"\\\\.\\Aken", GENERIC_READ, shareMode, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hAken == INVALID_HANDLE_VALUE) + { + ENSURE(GetLastError() == ERROR_FILE_NOT_FOUND); + SetLastError(0); return ERR::INVALID_HANDLE; // NOWARN (happens often due to security restrictions) + } } return INFO::OK; diff --git a/source/lib/sysdep/os/win/wdir_watch.cpp b/source/lib/sysdep/os/win/wdir_watch.cpp index 371ffc029e..7093c45a66 100644 --- a/source/lib/sysdep/os/win/wdir_watch.cpp +++ b/source/lib/sysdep/os/win/wdir_watch.cpp @@ -333,16 +333,12 @@ public: Status Poll(DirWatchNotifications& notifications) { +POLL_AGAIN: DWORD bytesTransferred; ULONG_PTR key; OVERLAPPED* ovl; - for(;;) // skip notifications of canceled watches - { - const Status ret = PollCompletionPort(hIOCP, 0, bytesTransferred, key, ovl); - if(ret == INFO::OK) - break; - if(GetLastError() == ERROR_OPERATION_ABORTED) - continue; // watch was canceled - ignore - return ret; - } + const Status ret = PollCompletionPort(hIOCP, 0, bytesTransferred, key, ovl); + if(ret == ERR::ABORTED) // watch was canceled + goto POLL_AGAIN; + RETURN_STATUS_IF_ERR(ret); DirWatchRequest* request = (DirWatchRequest*)key; request->RetrieveNotifications(notifications); diff --git a/source/lib/sysdep/os/win/whrt/whrt.cpp b/source/lib/sysdep/os/win/whrt/whrt.cpp index ef5cd495f0..12334c38ea 100644 --- a/source/lib/sysdep/os/win/whrt/whrt.cpp +++ b/source/lib/sysdep/os/win/whrt/whrt.cpp @@ -30,7 +30,7 @@ #include // _beginthreadex #include "lib/sysdep/cpu.h" -#include "lib/sysdep/os/win/win.h" +#include "lib/sysdep/os/win/wutil.h" #include "lib/sysdep/os/win/winit.h" #include "lib/sysdep/acpi.h" #include "lib/bits.h" @@ -261,6 +261,8 @@ static unsigned __stdcall UpdateThread(void* UNUSED(data)) static inline Status InitUpdateThread() { + WinScopedPreserveLastError s; // CreateEvent + // make sure our interval isn't too long // (counterBits can be 64 => Bit() would overflow => calculate period/2) const double period_2 = Bit(counterBits-1) / nominalFrequency; diff --git a/source/lib/sysdep/os/win/wiocp.cpp b/source/lib/sysdep/os/win/wiocp.cpp index 4696407cac..f489c54e92 100644 --- a/source/lib/sysdep/os/win/wiocp.cpp +++ b/source/lib/sysdep/os/win/wiocp.cpp @@ -20,13 +20,15 @@ Status PollCompletionPort(HANDLE hIOCP, DWORD timeout, DWORD& bytesTransferred, if(hIOCP == 0) return ERR::INVALID_HANDLE; // NOWARN (happens if called before the first Attach) + WinScopedPreserveLastError s; + bytesTransferred = 0; key = 0; ovl = 0; if(GetQueuedCompletionStatus(hIOCP, &bytesTransferred, &key, &ovl, timeout)) return INFO::OK; - if(GetLastError() == WAIT_TIMEOUT) - return ERR::AGAIN; // NOWARN (nothing pending) - else - return ERR::FAIL; // NOWARN (let caller decide what to do) + const Status ret = StatusFromWin(); + if(ret == ERR::AGAIN || ret == ERR::ABORTED) // avoid polluting last error + SetLastError(0); + return StatusFromWin(); // NOWARN (let caller decide what to do) } diff --git a/source/lib/sysdep/os/win/wposix/wfilesystem.cpp b/source/lib/sysdep/os/win/wposix/wfilesystem.cpp index bdd0cbdad3..68ae5b2d36 100644 --- a/source/lib/sysdep/os/win/wposix/wfilesystem.cpp +++ b/source/lib/sysdep/os/win/wposix/wfilesystem.cpp @@ -156,8 +156,10 @@ struct wdirent* wreaddir(WDIR* d) { if(!FindNextFileW(d->hFind, &d->findData)) { - if(GetLastError() != ERROR_NO_MORE_FILES) // an actual error occurred - WARN_IF_ERR(StatusFromWin()); + if(GetLastError() == ERROR_NO_MORE_FILES) + SetLastError(0); + else // unexpected error + DEBUG_WARN_ERR(StatusFromWin()); return 0; // end of directory or error } } diff --git a/source/lib/sysdep/os/win/wsdl.cpp b/source/lib/sysdep/os/win/wsdl.cpp index b106e1d65b..13c82d0da8 100644 --- a/source/lib/sysdep/os/win/wsdl.cpp +++ b/source/lib/sysdep/os/win/wsdl.cpp @@ -1485,6 +1485,8 @@ static void RedirectStdout() if(wutil_IsValidHandle(GetStdHandle(STD_OUTPUT_HANDLE))) return; + WinScopedPreserveLastError s; // ChangeExtension + // this code may be included in multiple executables sharing the same // directory, so include the executable's name in the filename. use its // full path since the current directory is unreliable. @@ -1495,9 +1497,12 @@ static void RedirectStdout() // that means stdout isn't associated with a lowio handle; _close is // called with fd = -1. oh well, there's nothing we can do. FILE* f = 0; - // (return value ignored - it indicates 'file already exists' even - // if f is valid) - (void)_wfreopen_s(&f, OsString(pathname).c_str(), L"wt", stdout); + errno_t ret = _wfreopen_s(&f, OsString(pathname).c_str(), L"wt", stdout); + // (ignore return value - it might indicate 'file already exists' even + // if f is valid, which is what actually counts) + UNUSED2(ret); + if(GetLastError() == ERROR_ALREADY_EXISTS) + SetLastError(0); // executable directory (probably Program Files) is read-only for // non-Administrators. we can't pick another directory because // ah_log_dir might not be valid until the app's init has run, diff --git a/source/lib/sysdep/os/win/wsysdep.cpp b/source/lib/sysdep/os/win/wsysdep.cpp index 41fe85d7a4..a8e8e8ef98 100644 --- a/source/lib/sysdep/os/win/wsysdep.cpp +++ b/source/lib/sysdep/os/win/wsysdep.cpp @@ -390,6 +390,7 @@ Status sys_get_module_filename(void* addr, OsPath& pathname) OsPath sys_ExecutablePathname() { + WinScopedPreserveLastError s; OsPath pathname; ENSURE(GetModulePathname(0, pathname) == INFO::OK); return pathname; diff --git a/source/lib/sysdep/os/win/wutil.cpp b/source/lib/sysdep/os/win/wutil.cpp index a8cce82d6e..2b1dc50035 100644 --- a/source/lib/sysdep/os/win/wutil.cpp +++ b/source/lib/sysdep/os/win/wutil.cpp @@ -145,7 +145,10 @@ Status StatusFromWin() case ERROR_PROC_NOT_FOUND: return ERR::NO_SYS; case ERROR_BUSY: + case WAIT_TIMEOUT: return ERR::AGAIN; + case ERROR_OPERATION_ABORTED: + return ERR::ABORTED; case ERROR_FILE_NOT_FOUND: return ERR::VFS_FILE_NOT_FOUND; case ERROR_PATH_NOT_FOUND: @@ -289,6 +292,8 @@ static void GetDirectories() wchar_t path[MAX_PATH]; // mandated by SHGetFolderPathW const HRESULT ret = SHGetFolderPathW(hwnd, CSIDL_APPDATA, token, 0, path); ENSURE(SUCCEEDED(ret)); + if(GetLastError() == ERROR_NO_TOKEN) // avoid polluting last error + SetLastError(0); appdataPath = new(wutil_Allocate(sizeof(OsPath))) OsPath(path); } } @@ -340,6 +345,14 @@ static void FreeUser32Dll() static void EnableLowFragmentationHeap() { + if(IsDebuggerPresent()) + { + // and the debug heap isn't explicitly disabled, + char* var = getenv("_NO_DEBUG_HEAP"); + if(!var || var[0] != '1') + return; // we can't enable the LFH + } + #if WINVER >= 0x0501 WUTIL_FUNC(pHeapSetInformation, BOOL, (HANDLE, HEAP_INFORMATION_CLASS, void*, size_t)); WUTIL_IMPORT_KERNEL32(HeapSetInformation, pHeapSetInformation);