diff --git a/misc/buffer-tests/harness/RemoteWorker.cc b/misc/buffer-tests/harness/RemoteWorker.cc index 303d2e7..506b8d8 100755 --- a/misc/buffer-tests/harness/RemoteWorker.cc +++ b/misc/buffer-tests/harness/RemoteWorker.cc @@ -39,7 +39,7 @@ RemoteWorker::RemoteWorker(const std::string &name) : RemoteWorker::RemoteWorker(SpawnParams params) : RemoteWorker(newWorkerName()) { - m_process = spawn(m_name, params); + m_process = spawn(m_name, params, nullptr); ASSERT(m_process != nullptr && "Could not create RemoteWorker"); m_valid = true; // Perform an RPC just to ensure that the worker process is ready, and @@ -53,12 +53,16 @@ RemoteWorker RemoteWorker::child(SpawnParams params) { return ret; } -RemoteWorker RemoteWorker::tryChild(SpawnParams params) { +RemoteWorker RemoteWorker::tryChild(SpawnParams params, DWORD *errCode) { RemoteWorker ret(newWorkerName()); cmd().u.spawn.spawnName = ret.m_name; cmd().u.spawn.spawnParams = params; rpc(Command::SpawnChild); - if (cmd().handle != nullptr) { + if (cmd().handle == nullptr) { + if (errCode != nullptr) { + *errCode = cmd().dword; + } + } else { BOOL dupSuccess = DuplicateHandle( m_process, cmd().handle, diff --git a/misc/buffer-tests/harness/RemoteWorker.h b/misc/buffer-tests/harness/RemoteWorker.h index 0915406..13c9a0c 100755 --- a/misc/buffer-tests/harness/RemoteWorker.h +++ b/misc/buffer-tests/harness/RemoteWorker.h @@ -21,7 +21,7 @@ public: RemoteWorker() : RemoteWorker(SpawnParams { false, CREATE_NEW_CONSOLE }) {} RemoteWorker(SpawnParams params); RemoteWorker child(SpawnParams params={}); - RemoteWorker tryChild(SpawnParams params={}); + RemoteWorker tryChild(SpawnParams params={}, DWORD *errCode=nullptr); ~RemoteWorker() { cleanup(); } bool valid() { return m_valid; } void exit(); diff --git a/misc/buffer-tests/harness/Spawn.cc b/misc/buffer-tests/harness/Spawn.cc index d051d81..01e10e1 100644 --- a/misc/buffer-tests/harness/Spawn.cc +++ b/misc/buffer-tests/harness/Spawn.cc @@ -20,7 +20,9 @@ static std::vector wstrToWVector(const std::wstring &str) { } // anonymous namespace -HANDLE spawn(const std::string &workerName, const SpawnParams ¶ms) { +HANDLE spawn(const std::string &workerName, + const SpawnParams ¶ms, + DWORD *lastError) { auto workerPath = pathDirName(getModuleFileName(NULL)) + "\\Worker.exe"; const std::wstring workerPathWStr = widenString(workerPath); const std::string cmdLine = "\"" + workerPath + "\" " + workerName; @@ -80,7 +82,11 @@ HANDLE spawn(const std::string &workerName, const SpawnParams ¶ms) { inheritList.data(), params.inheritCount * sizeof(HANDLE), nullptr, nullptr); - ASSERT(success && "UpdateProcThreadAttribute failed"); + if (!success) { + trace("Aborting: UpdateProcThreadAttribute failed: %s", + errorString(GetLastError()).c_str()); + abort(); + } } } @@ -95,7 +101,11 @@ HANDLE spawn(const std::string &workerName, const SpawnParams ¶ms) { NULL, NULL, &suix.StartupInfo, &pi); if (!success) { - trace("CreateProcessW failed: GetLastError=0x%x", GetLastError()); + if (lastError != nullptr) { + *lastError = GetLastError(); + } + trace("CreateProcessW failed: %s", + errorString(GetLastError()).c_str()); } else { ret = pi.hProcess; CloseHandle(pi.hThread); diff --git a/misc/buffer-tests/harness/Spawn.h b/misc/buffer-tests/harness/Spawn.h index 812a344..828162f 100644 --- a/misc/buffer-tests/harness/Spawn.h +++ b/misc/buffer-tests/harness/Spawn.h @@ -19,4 +19,6 @@ struct SpawnParams { } }; -HANDLE spawn(const std::string &workerName, const SpawnParams ¶ms); +HANDLE spawn(const std::string &workerName, + const SpawnParams ¶ms, + DWORD *lastError); diff --git a/misc/buffer-tests/harness/Util.cc b/misc/buffer-tests/harness/Util.cc index e3a6f45..2170e14 100644 --- a/misc/buffer-tests/harness/Util.cc +++ b/misc/buffer-tests/harness/Util.cc @@ -1,5 +1,7 @@ #include "Util.h" +#include + #include "UnicodeConversions.h" #include @@ -22,3 +24,61 @@ std::string getModuleFileName(HMODULE module) ASSERT(actual > 0 && actual < size); return narrowString(filename); } + +// Convert GetLastError()'s error code to a presentable message such as: +// +// <87:The parameter is incorrect.> +// +std::string errorString(DWORD errCode) { + // MSDN has this note about "Windows 10": + // + // Windows 10: + // + // LocalFree is not in the modern SDK, so it cannot be used to free + // the result buffer. Instead, use HeapFree (GetProcessHeap(), + // allocatedMessage). In this case, this is the same as calling + // LocalFree on memory. + // + // Important: LocalAlloc() has different options: LMEM_FIXED, and + // LMEM_MOVABLE. FormatMessage() uses LMEM_FIXED, so HeapFree can be + // used. If LMEM_MOVABLE is used, HeapFree cannot be used. + // + // My interpretation of this note is: + // * "Windows 10" really just means, "the latest MS SDK", which supports + // Windows 10, as well as older releases. + // * In every NT kernel ever, HeapFree is perfectly fine to use with + // LocalAlloc LMEM_FIXED allocations. + // * In every NT kernel ever, the FormatMessage buffer can be freed with + // HeapFree. + // The note is clumsy, though. Without clarity, I can't safely use + // HeapFree, but apparently LocalFree calls stop compiling in the newest + // SDK. + // + // Instead, I'll use a fixed-size buffer. + + std::stringstream ss; + ss << "<" << errCode << ":"; + std::vector msgBuf(1024); + DWORD ret = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + errCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + msgBuf.data(), + msgBuf.size(), + nullptr); + if (ret == 0) { + ss << "FormatMessageW failed:"; + ss << GetLastError(); + } else { + msgBuf[msgBuf.size() - 1] = L'\0'; + std::string msg = narrowString(std::wstring(msgBuf.data())); + if (msg.size() >= 2 && msg.substr(msg.size() - 2) == "\r\n") { + msg.resize(msg.size() - 2); + } + ss << msg; + } + ss << ">"; + return ss.str(); +} diff --git a/misc/buffer-tests/harness/Util.h b/misc/buffer-tests/harness/Util.h index 8d247ec..203a61c 100644 --- a/misc/buffer-tests/harness/Util.h +++ b/misc/buffer-tests/harness/Util.h @@ -7,3 +7,4 @@ std::string pathDirName(const std::string &path); std::string getModuleFileName(HMODULE module); +std::string errorString(DWORD errCode); diff --git a/misc/buffer-tests/harness/WorkerProgram.cc b/misc/buffer-tests/harness/WorkerProgram.cc index 8d288c5..7e8a21e 100644 --- a/misc/buffer-tests/harness/WorkerProgram.cc +++ b/misc/buffer-tests/harness/WorkerProgram.cc @@ -312,7 +312,8 @@ int main(int argc, char *argv[]) { case Command::SpawnChild: trace("Spawning child..."); cmd.handle = spawn(cmd.u.spawn.spawnName.str(), - cmd.u.spawn.spawnParams); + cmd.u.spawn.spawnParams, + &cmd.dword); if (cmd.handle != nullptr) { trace("Spawning child... pid %u", (unsigned int)GetProcessId(cmd.handle));