Propagate spawn GetLastError() so it can checked; print nice error messages
This commit is contained in:
parent
1b71ef07cc
commit
83c5e6de18
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -20,7 +20,9 @@ static std::vector<wchar_t> 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);
|
||||
|
@ -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);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "Util.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "UnicodeConversions.h"
|
||||
#include <WinptyAssert.h>
|
||||
|
||||
@ -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<wchar_t> 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();
|
||||
}
|
||||
|
@ -7,3 +7,4 @@
|
||||
|
||||
std::string pathDirName(const std::string &path);
|
||||
std::string getModuleFileName(HMODULE module);
|
||||
std::string errorString(DWORD errCode);
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user