Skip to main content
aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorTorbjörn Svensson2020-11-01 19:35:18 +0000
committerTorbjörn Svensson2020-11-03 07:55:05 +0000
commit35530c50ef70d64f271e54f32ea2c19be566cf55 (patch)
treeaa5c2d2528363722fddbfe2433a6a55dc109c997 /core
parentc598eedffaa71e9beeaecfe052865cf7bc6615f7 (diff)
downloadorg.eclipse.cdt-35530c50ef70d64f271e54f32ea2c19be566cf55.tar.gz
org.eclipse.cdt-35530c50ef70d64f271e54f32ea2c19be566cf55.tar.xz
org.eclipse.cdt-35530c50ef70d64f271e54f32ea2c19be566cf55.zip
Bug 568079: Rework spawner to avoid memory leaks on Win32
Change-Id: I1253351d47d52e848867d7f9df61a66f9bd82d41 Signed-off-by: Torbjörn Svensson <azoff@svenskalinuxforeningen.se>
Diffstat (limited to 'core')
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c748
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/starter.c324
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/util.c64
-rw-r--r--core/org.eclipse.cdt.core.native/native_src/win/util.h17
-rwxr-xr-xcore/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/pty.dllbin1037433 -> 1037980 bytes
-rwxr-xr-xcore/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/spawner.dllbin335721 -> 334776 bytes
-rwxr-xr-xcore/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/starter.exebin402292 -> 402854 bytes
7 files changed, 579 insertions, 574 deletions
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c b/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c
index 38959c98125..feaf4faca5a 100644
--- a/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c
+++ b/core/org.eclipse.cdt.core.native/native_src/win/Win32ProcessEx.c
@@ -36,6 +36,11 @@
#define MAX_PROCS (100) // Maximum number of simultaneously running processes
+typedef struct _eventInfo {
+ HANDLE handle;
+ wchar_t *name;
+} EventInfo_t;
+
// Process description block. Should be created for each launched process
typedef struct _procInfo {
int pid; // Process ID
@@ -43,15 +48,15 @@ typedef struct _procInfo {
// (actually this impossible from OS point of view but it is still possible
// a clash of new created and already finished process with one and the same PID.
// 4 events connected to this process (see starter)
- HANDLE eventBreak; // signaled when Spawner.interrupt() is called; mildest of the terminate requests (SIGINT signal
- // in UNIX world)
- HANDLE eventWait;
- HANDLE eventTerminate; // signaled when Spawner.terminate() is called; more forceful terminate request (SIGTERM
- // signal in UNIX world)
- HANDLE eventKill; // signaled when Spawner.kill() is called; most forceful terminate request (SIGKILL signal in UNIX
- // world)
- HANDLE eventCtrlc; // signaled when Spawner.interruptCTRLC() is called; like interrupt() but sends CTRL-C in all
- // cases, even when inferior is a Cygwin program
+ EventInfo_t eventBreak; // signaled when Spawner.interrupt() is called; mildest of the terminate requests (SIGINT
+ // signal in UNIX world)
+ EventInfo_t eventWait;
+ EventInfo_t eventTerminate; // signaled when Spawner.terminate() is called; more forceful terminate request (SIGTERM
+ // signal in UNIX world)
+ EventInfo_t eventKill; // signaled when Spawner.kill() is called; most forceful terminate request (SIGKILL signal in
+ // UNIX world)
+ EventInfo_t eventCtrlc; // signaled when Spawner.interruptCTRLC() is called; like interrupt() but sends CTRL-C in
+ // all cases, even when inferior is a Cygwin program
} procInfo_t, *pProcInfo_t;
static int procCounter = 0; // Number of running processes
@@ -68,9 +73,6 @@ pProcInfo_t findProcInfo(int pid);
// We launch separate thread for each project to trap it termination
void _cdecl waitProcTermination(void *pv);
-// This is a helper function to prevent losing of quotation marks
-static int copyTo(wchar_t *target, const wchar_t *source, int cpyLenght, int availSpace);
-
// Use this function to clean project descriptor and return it to the pool of available blocks.
static void cleanUpProcBlock(pProcInfo_t pCurProcInfo);
@@ -113,20 +115,217 @@ extern "C"
return -1;
}
-void ensureSize(wchar_t **ptr, int *psize, int requiredLength) {
- int size = *psize;
- if (requiredLength > size) {
- size = 2 * size;
- if (size < requiredLength) {
- size = requiredLength;
+static bool createStandardNamedPipe(HANDLE *handle, DWORD stdHandle, int pid, int counter) {
+ wchar_t pipeName[PIPE_NAME_LENGTH];
+ DWORD dwOpenMode;
+
+ switch (stdHandle) {
+ case STD_INPUT_HANDLE:
+ BUILD_PIPE_NAME(pipeName, L"stdin", pid, counter);
+ dwOpenMode = PIPE_ACCESS_OUTBOUND;
+ break;
+ case STD_OUTPUT_HANDLE:
+ BUILD_PIPE_NAME(pipeName, L"stdout", pid, counter);
+ dwOpenMode = PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED;
+ break;
+ case STD_ERROR_HANDLE:
+ BUILD_PIPE_NAME(pipeName, L"stderr", pid, counter);
+ dwOpenMode = PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED;
+ break;
+ default:
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Invalid STD handle given %i", stdHandle);
+ }
+ return false;
+ }
+
+ HANDLE pipe = CreateNamedPipeW(pipeName, dwOpenMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL);
+ if (INVALID_HANDLE_VALUE == pipe) {
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Failed to create named pipe: %s\n", pipeName);
+ }
+ return false;
+ }
+
+ SetHandleInformation(pipe, HANDLE_FLAG_INHERIT, TRUE);
+
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Successfully created pipe %s -> %p\n", pipeName, pipe);
+ }
+
+ *handle = pipe;
+ return true;
+}
+
+static bool createNamedEvent(EventInfo_t *eventInfo, BOOL manualReset, const wchar_t *prefix, int pid, int counter) {
+ wchar_t eventName[50];
+ swprintf(eventName, sizeof(eventName) / sizeof(eventName[0]), L"%s%04x%08x", prefix, pid, counter);
+
+ HANDLE event = CreateEventW(NULL, manualReset, FALSE, eventName);
+ if (!event) {
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Failed to create event %s -> %i\n", eventName, GetLastError());
+ }
+ return false;
+ } else if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Event %s already exist -> %p\n", eventName, event);
+ }
+ return false;
+ }
+
+ eventInfo->handle = event;
+ eventInfo->name = wcsdup(eventName);
+
+ if (!eventInfo->name) {
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Failed to allocate memory for event %s -> %p\n", eventName, event);
}
- *ptr = (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
- if (*ptr) {
- *psize = size;
+ return false;
+ }
+
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Successfully created event %s -> %p\n", eventName, event);
+ }
+
+ return true;
+}
+
+static bool createCommandLine(JNIEnv *env, jobjectArray cmdarray, wchar_t **cmdLine, const wchar_t *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ wchar_t *buffer = NULL;
+ int size = MAX_CMD_SIZE;
+ int required = 0;
+ do {
+ // Free previous buffer
+ free(buffer);
+
+ size *= 2;
+ buffer = (wchar_t *)malloc(size * sizeof(wchar_t));
+
+ if (buffer) {
+ // Try to format the string
+ required = vswprintf(buffer, size, fmt, ap);
} else {
- *psize = 0;
+ // malloc failed, clean up and return
+ va_end(ap);
+ ThrowByName(env, "java/io/IOException", "Not enough memory");
+ return false;
+ }
+ } while (size <= required);
+ va_end(ap);
+
+ int nPos = wcslen(buffer);
+ int nCmdTokens = (*env)->GetArrayLength(env, cmdarray);
+ for (int i = 0; i < nCmdTokens; ++i) {
+ jstring item = (jstring)(*env)->GetObjectArrayElement(env, cmdarray, i);
+ jsize len = (*env)->GetStringLength(env, item);
+ const jchar *str = (*env)->GetStringChars(env, item, NULL);
+ if (str) {
+ required = nPos + len + 2; // 2 => space + \0
+ if (required > 32 * 1024) {
+ free(buffer);
+ ThrowByName(env, "java/io/IOException", "Command line too long");
+ return false;
+ }
+
+ while (1) {
+ // Ensure enough space in buffer
+ if (required > size) {
+ size *= 2;
+ if (size < required) {
+ size = required;
+ }
+
+ wchar_t *tmp = (wchar_t *)realloc(buffer, size * sizeof(wchar_t));
+ if (tmp) {
+ // Allocation successful
+ buffer = tmp;
+ } else {
+ // Failed to realloc memory
+ free(buffer);
+ ThrowByName(env, "java/io/IOException", "Not enough memory");
+ return false;
+ }
+ }
+
+ int nCpyLen = copyTo(buffer + nPos, (const wchar_t *)str, len, size - nPos);
+ if (nCpyLen < 0) { // Buffer too small
+ // Do a real count of number of chars required
+ required = nPos + copyTo(NULL, (const wchar_t *)str, len, INT_MAX) + 2; // 2 => space + \0
+ continue;
+ }
+
+ // Buffer was big enough.
+ nPos += nCpyLen;
+ break;
+ }
+
+ buffer[nPos++] = _T(' ');
+ buffer[nPos] = _T('\0');
+ (*env)->ReleaseStringChars(env, item, str);
+ } else {
+ free(buffer);
+ ThrowByName(env, "java/io/IOException", "Command line contained null string");
+ return false;
}
}
+
+ *cmdLine = buffer;
+ return true;
+}
+
+static bool createEnvironmentBlock(JNIEnv *env, jobjectArray envp, wchar_t **block) {
+ int nEnvVars = (*env)->GetArrayLength(env, envp);
+
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"There are %i environment variables \n", nEnvVars);
+ }
+
+ if (nEnvVars == 0) {
+ *block = NULL;
+ return true;
+ }
+
+ int nPos = 0;
+ int nBlkSize = MAX_ENV_SIZE;
+ wchar_t *buffer = (wchar_t *)malloc(nBlkSize * sizeof(wchar_t));
+ for (int i = 0; i < nEnvVars; ++i) {
+ jstring item = (jstring)(*env)->GetObjectArrayElement(env, envp, i);
+ jsize len = (*env)->GetStringLength(env, item);
+ const jchar *str = (*env)->GetStringChars(env, item, 0);
+ if (str) {
+ while (nBlkSize - nPos <= len + 2) { // +2 for two '\0'
+ nBlkSize += MAX_ENV_SIZE;
+ wchar_t *tmp = (wchar_t *)realloc(buffer, nBlkSize * sizeof(wchar_t));
+ if (tmp) {
+ buffer = tmp;
+ } else {
+ free(buffer);
+ ThrowByName(env, "java/io/IOException", "Not enough memory");
+ return false;
+ }
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Realloc environment block; new length is %i \n", nBlkSize);
+ }
+ }
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"%s\n", (const wchar_t *)str);
+ }
+ wcsncpy(buffer + nPos, (const wchar_t *)str, len);
+ nPos += len;
+ buffer[nPos++] = _T('\0');
+ (*env)->ReleaseStringChars(env, item, str);
+ }
+ }
+ buffer[nPos] = _T('\0');
+ *block = buffer;
+
+ return true;
}
#ifdef __cplusplus
@@ -135,202 +334,95 @@ extern "C"
JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_Spawner_exec0(JNIEnv *env, jobject process, jobjectArray cmdarray,
jobjectArray envp, jstring dir, jobjectArray channels) {
- HANDLE stdHandles[3];
- PROCESS_INFORMATION pi = {0}, *piCopy;
- STARTUPINFOW si;
- DWORD flags = 0;
- wchar_t *cwd = NULL;
- int ret = 0;
- int nCmdLineLength = 0;
- wchar_t *szCmdLine = 0;
- int nBlkSize = MAX_ENV_SIZE;
- wchar_t *szEnvBlock = NULL;
- jsize nCmdTokens = 0;
- jsize nEnvVars = 0;
- DWORD pid = GetCurrentProcessId();
- int nPos;
- pProcInfo_t pCurProcInfo;
-
- // This needs to be big enough to contain the name of the event used when calling CreateEventW bellow.
- // It is made of a prefix (7 characters max) plus the value of a pointer that gets output in characters.
- // This will be bigger in the case of 64 bit.
- static const int MAX_EVENT_NAME_LENGTH = 50;
- wchar_t eventBreakName[MAX_EVENT_NAME_LENGTH];
- wchar_t eventWaitName[MAX_EVENT_NAME_LENGTH];
- wchar_t eventTerminateName[MAX_EVENT_NAME_LENGTH];
- wchar_t eventKillName[MAX_EVENT_NAME_LENGTH];
- wchar_t eventCtrlcName[MAX_EVENT_NAME_LENGTH];
- int nLocalCounter;
- wchar_t inPipeName[PIPE_NAME_LENGTH];
- wchar_t outPipeName[PIPE_NAME_LENGTH];
- wchar_t errPipeName[PIPE_NAME_LENGTH];
- jclass channelClass = NULL;
- jmethodID channelConstructor = NULL;
-
if (!channels) {
ThrowByName(env, "java/io/IOException", "Channels can't be null");
return 0;
}
- channelClass = (*env)->FindClass(env, "org/eclipse/cdt/utils/spawner/Spawner$WinChannel");
+ jclass channelClass = (*env)->FindClass(env, "org/eclipse/cdt/utils/spawner/Spawner$WinChannel");
if (!channelClass) {
ThrowByName(env, "java/io/IOException", "Unable to find channel class");
return 0;
}
- channelConstructor = (*env)->GetMethodID(env, channelClass, "<init>", "(J)V");
+ jmethodID channelConstructor = (*env)->GetMethodID(env, channelClass, "<init>", "(J)V");
if (!channelConstructor) {
ThrowByName(env, "java/io/IOException", "Unable to find channel constructor");
return 0;
}
- nCmdLineLength = MAX_CMD_SIZE;
- szCmdLine = (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
- szCmdLine[0] = _T('\0');
if ((HIBYTE(LOWORD(GetVersion()))) & 0x80) {
ThrowByName(env, "java/io/IOException", "Does not support Windows 3.1/95/98/Me");
return 0;
}
- if (cmdarray == 0) {
+ if (!cmdarray) {
ThrowByName(env, "java/lang/NullPointerException", "No command line specified");
return 0;
}
- ZeroMemory(stdHandles, sizeof(stdHandles));
+ DWORD pid = GetCurrentProcessId();
// Create pipe names
EnterCriticalSection(&cs);
- swprintf(inPipeName, sizeof(inPipeName) / sizeof(inPipeName[0]), L"\\\\.\\pipe\\stdin%08i%010i", pid, nCounter);
- swprintf(outPipeName, sizeof(outPipeName) / sizeof(outPipeName[0]), L"\\\\.\\pipe\\stdout%08i%010i", pid, nCounter);
- swprintf(errPipeName, sizeof(errPipeName) / sizeof(errPipeName[0]), L"\\\\.\\pipe\\stderr%08i%010i", pid, nCounter);
- nLocalCounter = nCounter;
- ++nCounter;
+ int nLocalCounter = nCounter++;
LeaveCriticalSection(&cs);
- if ((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateNamedPipeW(
- inPipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
- (INVALID_HANDLE_VALUE ==
- (stdHandles[1] = CreateNamedPipeW(outPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
- PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
- (INVALID_HANDLE_VALUE ==
- (stdHandles[2] = CreateNamedPipeW(errPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
- PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL)))) {
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
+ HANDLE stdHandles[] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ if (!createStandardNamedPipe(&stdHandles[0], STD_INPUT_HANDLE, pid, nLocalCounter) ||
+ !createStandardNamedPipe(&stdHandles[1], STD_OUTPUT_HANDLE, pid, nLocalCounter) ||
+ !createStandardNamedPipe(&stdHandles[2], STD_ERROR_HANDLE, pid, nLocalCounter)) {
+ CLOSE_HANDLES(stdHandles);
ThrowByName(env, "java/io/IOException", "CreatePipe");
return 0;
}
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Opened pipes: %s, %s, %s\n", inPipeName, outPipeName, errPipeName);
- }
-
- nCmdTokens = (*env)->GetArrayLength(env, cmdarray);
- nEnvVars = (*env)->GetArrayLength(env, envp);
-
- pCurProcInfo = createProcInfo();
-
+ pProcInfo_t pCurProcInfo = createProcInfo();
if (!pCurProcInfo) {
+ CLOSE_HANDLES(stdHandles);
ThrowByName(env, "java/io/IOException", "Too many processes");
return 0;
}
- // Construct starter's command line
- swprintf(eventBreakName, sizeof(eventBreakName) / sizeof(eventBreakName[0]), L"SABreak%04x%08x", pid,
- nLocalCounter);
- swprintf(eventWaitName, sizeof(eventWaitName) / sizeof(eventWaitName[0]), L"SAWait%04x%08x", pid, nLocalCounter);
- swprintf(eventTerminateName, sizeof(eventTerminateName) / sizeof(eventTerminateName[0]), L"SATerm%04x%08x", pid,
- nLocalCounter);
- swprintf(eventKillName, sizeof(eventKillName) / sizeof(eventKillName[0]), L"SAKill%04x%08x", pid, nLocalCounter);
- swprintf(eventCtrlcName, sizeof(eventCtrlcName) / sizeof(eventCtrlcName[0]), L"SACtrlc%04x%08x", pid,
- nLocalCounter);
-
- pCurProcInfo->eventBreak = CreateEventW(NULL, FALSE, FALSE, eventBreakName);
- if (!pCurProcInfo->eventBreak || GetLastError() == ERROR_ALREADY_EXISTS) {
+ // Create events
+ if (!createNamedEvent(&pCurProcInfo->eventBreak, FALSE, L"SABreak", pid, nLocalCounter) ||
+ !createNamedEvent(&pCurProcInfo->eventWait, TRUE, L"SAWait", pid, nLocalCounter) ||
+ !createNamedEvent(&pCurProcInfo->eventTerminate, FALSE, L"SATerm", pid, nLocalCounter) ||
+ !createNamedEvent(&pCurProcInfo->eventKill, FALSE, L"SAKill", pid, nLocalCounter) ||
+ !createNamedEvent(&pCurProcInfo->eventCtrlc, FALSE, L"SACtrlc", pid, nLocalCounter)) {
+ cleanUpProcBlock(pCurProcInfo);
+ CLOSE_HANDLES(stdHandles);
ThrowByName(env, "java/io/IOException", "Cannot create event");
return 0;
}
- pCurProcInfo->eventWait = CreateEventW(NULL, TRUE, FALSE, eventWaitName);
- pCurProcInfo->eventTerminate = CreateEventW(NULL, FALSE, FALSE, eventTerminateName);
- pCurProcInfo->eventKill = CreateEventW(NULL, FALSE, FALSE, eventKillName);
- pCurProcInfo->eventCtrlc = CreateEventW(NULL, FALSE, FALSE, eventCtrlcName);
-
- swprintf(szCmdLine, nCmdLineLength, L"\"%sstarter.exe\" %i %i %s %s %s %s %s ", path, pid, nLocalCounter,
- eventBreakName, eventWaitName, eventTerminateName, eventKillName, eventCtrlcName);
- nPos = wcslen(szCmdLine);
// Prepare command line
- for (int i = 0; i < nCmdTokens; ++i) {
- jstring item = (jstring)(*env)->GetObjectArrayElement(env, cmdarray, i);
- jsize len = (*env)->GetStringLength(env, item);
- int nCpyLen;
- const wchar_t *str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
- if (str) {
- int requiredSize = nPos + len + 2;
- if (requiredSize > 32 * 1024) {
- ThrowByName(env, "java/io/IOException", "Command line too long");
- return 0;
- }
- ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
- if (!szCmdLine) {
- ThrowByName(env, "java/io/IOException", "Not enough memory");
- return 0;
- }
-
- if (0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, nCmdLineLength - nPos))) {
- ThrowByName(env, "java/io/IOException", "Command line too long");
- return 0;
- }
- nPos += nCpyLen;
- szCmdLine[nPos] = _T(' ');
- ++nPos;
- (*env)->ReleaseStringChars(env, item, (const jchar *)str);
- }
- }
- szCmdLine[nPos] = _T('\0');
-
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"There are %i environment variables \n", nEnvVars);
+ wchar_t *cmdLine = NULL;
+ if (!createCommandLine(env, cmdarray, &cmdLine, L"\"%sstarter.exe\" %i %i %s %s %s %s %s ", path, //
+ pid, //
+ nLocalCounter, //
+ pCurProcInfo->eventBreak.name, //
+ pCurProcInfo->eventWait.name, //
+ pCurProcInfo->eventTerminate.name, //
+ pCurProcInfo->eventKill.name, //
+ pCurProcInfo->eventCtrlc.name)) {
+ // Exception already thrown, just clean up
+ cleanUpProcBlock(pCurProcInfo);
+ CLOSE_HANDLES(stdHandles);
+ return 0;
}
// Prepare environment block
- if (nEnvVars > 0) {
- nPos = 0;
- szEnvBlock = (wchar_t *)malloc(nBlkSize * sizeof(wchar_t));
- for (int i = 0; i < nEnvVars; ++i) {
- jstring item = (jstring)(*env)->GetObjectArrayElement(env, envp, i);
- jsize len = (*env)->GetStringLength(env, item);
- const wchar_t *str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
- if (str) {
- while ((nBlkSize - nPos) <= (len + 2)) { // +2 for two '\0'
- nBlkSize += MAX_ENV_SIZE;
- szEnvBlock = (wchar_t *)realloc(szEnvBlock, nBlkSize * sizeof(wchar_t));
- if (!szEnvBlock) {
- ThrowByName(env, "java/io/IOException", "Not enough memory");
- return 0;
- }
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Realloc environment block; new length is %i \n", nBlkSize);
- }
- }
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"%s\n", str);
- }
- wcsncpy(szEnvBlock + nPos, str, len);
- nPos += len;
- szEnvBlock[nPos] = _T('\0');
- ++nPos;
- (*env)->ReleaseStringChars(env, item, (const jchar *)str);
- }
- }
- szEnvBlock[nPos] = _T('\0');
+ wchar_t *envBlock = NULL;
+ if (!createEnvironmentBlock(env, envp, &envBlock)) {
+ // Exception already thrown, just clean up
+ free(cmdLine);
+ cleanUpProcBlock(pCurProcInfo);
+ CLOSE_HANDLES(stdHandles);
+ return 0;
}
+ wchar_t *cwd = NULL;
if (dir) {
const jchar *str = (*env)->GetStringChars(env, dir, NULL);
if (str) {
@@ -339,68 +431,54 @@ extern "C"
}
}
+ STARTUPINFOW si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; // Processes in the Process Group are hidden
- SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, FALSE);
- SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, FALSE);
- SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, FALSE);
-
- flags = CREATE_NEW_CONSOLE;
+ DWORD flags = CREATE_NEW_CONSOLE;
flags |= CREATE_NO_WINDOW;
flags |= CREATE_UNICODE_ENVIRONMENT;
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(szCmdLine);
+ cdtTrace(cmdLine);
}
+
// launches starter; we need it to create another console group to correctly process
// emulation of SYSint signal (Ctrl-C)
- ret = CreateProcessW(0, /* executable name */
- szCmdLine, /* command line */
- 0, /* process security attribute */
- 0, /* thread security attribute */
- FALSE, /* inherits system handles */
- flags, /* normal attached process */
- szEnvBlock, /* environment block */
- cwd, /* change to the new current directory */
- &si, /* (in) startup information */
- &pi); /* (out) process information */
+ PROCESS_INFORMATION pi = {0};
+ int ret = CreateProcessW(NULL, /* executable name */
+ cmdLine, /* command line */
+ 0, /* process security attribute */
+ 0, /* thread security attribute */
+ FALSE, /* inherits system handles */
+ flags, /* normal attached process */
+ envBlock, /* environment block */
+ cwd, /* change to the new current directory */
+ &si, /* (in) startup information */
+ &pi); /* (out) process information */
free(cwd);
- free(szEnvBlock);
- free(szCmdLine);
+ free(envBlock);
+ free(cmdLine);
- if (!ret) { // Launching error
- char *lpMsgBuf;
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
- FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (char *)&lpMsgBuf, 0, NULL);
- ThrowByName(env, "java/io/IOException", lpMsgBuf);
- // Free the buffer.
- LocalFree(lpMsgBuf);
- cleanUpProcBlock(pCurProcInfo);
- ret = -1;
- } else {
+ if (ret) {
HANDLE h[2];
- int what;
EnterCriticalSection(&cs);
pCurProcInfo->pid = pi.dwProcessId;
- h[0] = pCurProcInfo->eventWait;
+ h[0] = pCurProcInfo->eventWait.handle;
h[1] = pi.hProcess;
- what = WaitForMultipleObjects(2, h, FALSE, INFINITE);
+ int what = WaitForMultipleObjects(2, h, FALSE, INFINITE);
if (what != WAIT_OBJECT_0) { // CreateProcess failed
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Process %i failed\n", pi.dwProcessId);
}
cleanUpProcBlock(pCurProcInfo);
+ CLOSE_HANDLES(stdHandles);
ThrowByName(env, "java/io/IOException", "Launching failed");
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Process failed\n");
@@ -416,7 +494,7 @@ extern "C"
// do the cleanup so launch the according thread
// create a copy of the PROCESS_INFORMATION as this might get destroyed
- piCopy = (PROCESS_INFORMATION *)malloc(sizeof(PROCESS_INFORMATION));
+ PROCESS_INFORMATION *piCopy = (PROCESS_INFORMATION *)malloc(sizeof(PROCESS_INFORMATION));
memcpy(piCopy, &pi, sizeof(PROCESS_INFORMATION));
_beginthread(waitProcTermination, 0, (void *)piCopy);
@@ -425,6 +503,17 @@ extern "C"
}
}
LeaveCriticalSection(&cs);
+ } else { // Launching error
+ char *lpMsgBuf;
+ CLOSE_HANDLES(stdHandles);
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (char *)&lpMsgBuf, 0, NULL);
+ ThrowByName(env, "java/io/IOException", lpMsgBuf);
+ // Free the buffer.
+ LocalFree(lpMsgBuf);
+ cleanUpProcBlock(pCurProcInfo);
+ ret = -1;
}
CloseHandle(pi.hThread);
@@ -446,94 +535,21 @@ extern "C"
Java_org_eclipse_cdt_utils_spawner_Spawner_exec1(JNIEnv *env, jobject process, jobjectArray cmdarray,
jobjectArray envp, jstring dir) {
- SECURITY_ATTRIBUTES sa;
- PROCESS_INFORMATION pi = {0};
- STARTUPINFOW si;
- DWORD flags = 0;
- wchar_t *cwd = NULL;
- wchar_t *envBlk = NULL;
- int ret = 0;
- jsize nCmdTokens = 0;
- jsize nEnvVars = 0;
- int i;
- int nPos;
- int nCmdLineLength = 0;
- wchar_t *szCmdLine = 0;
- int nBlkSize = MAX_ENV_SIZE;
- wchar_t *szEnvBlock = NULL;
-
- nCmdLineLength = MAX_CMD_SIZE;
- szCmdLine = (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
- szCmdLine[0] = 0;
-
- sa.nLength = sizeof(sa);
- sa.lpSecurityDescriptor = 0;
- sa.bInheritHandle = TRUE;
-
- nCmdTokens = (*env)->GetArrayLength(env, cmdarray);
- nEnvVars = (*env)->GetArrayLength(env, envp);
-
- nPos = 0;
-
// Prepare command line
- for (i = 0; i < nCmdTokens; ++i) {
- jstring item = (jstring)(*env)->GetObjectArrayElement(env, cmdarray, i);
- jsize len = (*env)->GetStringLength(env, item);
- int nCpyLen;
- const wchar_t *str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
- if (str) {
- int requiredSize = nPos + len + 2;
- if (requiredSize > 32 * 1024) {
- ThrowByName(env, "java/io/IOException", "Command line too long");
- return 0;
- }
- ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
- if (!szCmdLine) {
- ThrowByName(env, "java/io/IOException", "Not enough memory");
- return 0;
- }
-
- if (0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, nCmdLineLength - nPos))) {
- ThrowByName(env, "java/io/Exception", "Command line too long");
- return 0;
- }
- nPos += nCpyLen;
- szCmdLine[nPos] = _T(' ');
- ++nPos;
- (*env)->ReleaseStringChars(env, item, (const jchar *)str);
- }
+ wchar_t *cmdLine = NULL;
+ if (!createCommandLine(env, cmdarray, &cmdLine, L"")) {
+ // Exception already thrown
+ return 0;
}
- szCmdLine[nPos] = _T('\0');
-
// Prepare environment block
- if (nEnvVars > 0) {
- szEnvBlock = (wchar_t *)malloc(nBlkSize * sizeof(wchar_t));
- nPos = 0;
- for (i = 0; i < nEnvVars; ++i) {
- jstring item = (jstring)(*env)->GetObjectArrayElement(env, envp, i);
- jsize len = (*env)->GetStringLength(env, item);
- const wchar_t *str = (const wchar_t *)(*env)->GetStringChars(env, item, 0);
- if (str) {
- while ((nBlkSize - nPos) <= (len + 2)) { // +2 for two '\0'
- nBlkSize += MAX_ENV_SIZE;
- szEnvBlock = (wchar_t *)realloc(szEnvBlock, nBlkSize * sizeof(wchar_t));
- if (!szEnvBlock) {
- ThrowByName(env, "java/io/Exception", "Not enough memory");
- return 0;
- }
- }
- wcsncpy(szEnvBlock + nPos, str, len);
- nPos += len;
- szEnvBlock[nPos] = _T('\0');
- ++nPos;
- (*env)->ReleaseStringChars(env, item, (const jchar *)str);
- }
- }
- szEnvBlock[nPos] = _T('\0');
- envBlk = szEnvBlock;
+ wchar_t *envBlock = NULL;
+ if (!createEnvironmentBlock(env, envp, &envBlock)) {
+ free(cmdLine);
+ return 0;
}
+ wchar_t *cwd = NULL;
if (dir) {
const jchar *str = (*env)->GetStringChars(env, dir, NULL);
if (str) {
@@ -542,27 +558,35 @@ extern "C"
}
}
+ STARTUPINFOW si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
- flags = CREATE_NEW_CONSOLE;
+ DWORD flags = CREATE_NEW_CONSOLE;
flags |= CREATE_UNICODE_ENVIRONMENT;
- ret = CreateProcessW(0, /* executable name */
- szCmdLine, /* command line */
- 0, /* process security attribute */
- 0, /* thread security attribute */
- TRUE, /* inherits system handles */
- flags, /* normal attached process */
- envBlk, /* environment block */
- cwd, /* change to the new current directory */
- &si, /* (in) startup information */
- &pi); /* (out) process information */
+
+ PROCESS_INFORMATION pi = {0};
+ int ret = CreateProcessW(NULL, /* executable name */
+ cmdLine, /* command line */
+ 0, /* process security attribute */
+ 0, /* thread security attribute */
+ TRUE, /* inherits system handles */
+ flags, /* normal attached process */
+ envBlock, /* environment block */
+ cwd, /* change to the new current directory */
+ &si, /* (in) startup information */
+ &pi); /* (out) process information */
free(cwd);
- free(szEnvBlock);
- free(szCmdLine);
+ free(cmdLine);
+ free(envBlock);
- if (!ret) { // error
+ if (ret) {
+ // Clean-up
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ ret = (long)pi.dwProcessId; // hProcess;
+ } else { // error
char *lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
@@ -572,11 +596,6 @@ extern "C"
// Free the buffer.
LocalFree(lpMsgBuf);
ret = -1;
- } else {
- // Clean-up
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
- ret = (long)pi.dwProcessId; // hProcess;
}
return ret;
@@ -628,7 +647,7 @@ extern "C"
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Spawner received TERM signal for process %i\n", pCurProcInfo->pid);
}
- SetEvent(pCurProcInfo->eventTerminate);
+ SetEvent(pCurProcInfo->eventTerminate.handle);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Spawner signaled TERM event\n");
}
@@ -639,21 +658,21 @@ extern "C"
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Spawner received KILL signal for process %i\n", pCurProcInfo->pid);
}
- SetEvent(pCurProcInfo->eventKill);
+ SetEvent(pCurProcInfo->eventKill.handle);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Spawner signaled KILL event\n");
}
ret = 0;
break;
case SIG_INT:
- ResetEvent(pCurProcInfo->eventWait);
- SetEvent(pCurProcInfo->eventBreak);
- ret = (WaitForSingleObject(pCurProcInfo->eventWait, 100) == WAIT_OBJECT_0);
+ ResetEvent(pCurProcInfo->eventWait.handle);
+ SetEvent(pCurProcInfo->eventBreak.handle);
+ ret = (WaitForSingleObject(pCurProcInfo->eventWait.handle, 100) == WAIT_OBJECT_0);
break;
case CTRLC:
- ResetEvent(pCurProcInfo->eventWait);
- SetEvent(pCurProcInfo->eventCtrlc);
- ret = (WaitForSingleObject(pCurProcInfo->eventWait, 100) == WAIT_OBJECT_0);
+ ResetEvent(pCurProcInfo->eventWait.handle);
+ SetEvent(pCurProcInfo->eventCtrlc.handle);
+ ret = (WaitForSingleObject(pCurProcInfo->eventWait.handle, 100) == WAIT_OBJECT_0);
break;
default:
break;
@@ -772,27 +791,20 @@ pProcInfo_t findProcInfo(int uid) {
// pCurProcInfo - pointer to descriptor to clean up
// Return : no
void cleanUpProcBlock(pProcInfo_t pCurProcInfo) {
- if (0 != pCurProcInfo->eventBreak) {
- CloseHandle(pCurProcInfo->eventBreak);
- pCurProcInfo->eventBreak = 0;
- }
- if (0 != pCurProcInfo->eventWait) {
- CloseHandle(pCurProcInfo->eventWait);
- pCurProcInfo->eventWait = 0;
- }
- if (0 != pCurProcInfo->eventTerminate) {
- CloseHandle(pCurProcInfo->eventTerminate);
- pCurProcInfo->eventTerminate = 0;
- }
-
- if (0 != pCurProcInfo->eventKill) {
- CloseHandle(pCurProcInfo->eventKill);
- pCurProcInfo->eventKill = 0;
- }
+ EventInfo_t *eventInfos[] = {
+ &pCurProcInfo->eventBreak, &pCurProcInfo->eventWait, &pCurProcInfo->eventTerminate,
+ &pCurProcInfo->eventKill, &pCurProcInfo->eventCtrlc,
+ };
+
+ for (int i = 0; i < sizeof(eventInfos) / sizeof(eventInfos[0]); i++) {
+ EventInfo_t *p = eventInfos[i];
+ if (p->handle) {
+ CloseHandle(p->handle);
+ p->handle = NULL;
+ }
- if (0 != pCurProcInfo->eventCtrlc) {
- CloseHandle(pCurProcInfo->eventCtrlc);
- pCurProcInfo->eventCtrlc = 0;
+ free(p->name);
+ p->name = NULL;
}
pCurProcInfo->pid = 0;
@@ -822,69 +834,3 @@ void _cdecl waitProcTermination(void *pv) {
free(pi);
}
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Use this utility program to process correctly quotation marks in the command line
-// Arguments:
-// target - string to copy to
-// source - string to copy from
-// cpyLength - copy length
-// availSpace - size of the target buffer
-// Return :number of bytes used in target, or -1 in case of error
-/////////////////////////////////////////////////////////////////////////////////////
-int copyTo(wchar_t *target, const wchar_t *source, int cpyLength, int availSpace) {
- bool bSlash = false;
- int i = 0, j = 0;
-
- enum { QUOTATION_DO, QUOTATION_DONE, QUOTATION_NONE } nQuotationMode = QUOTATION_DO;
-
- if (availSpace <= cpyLength) { // = to reserve space for final '\0'
- return -1;
- }
-
- if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
- nQuotationMode = QUOTATION_DONE;
- } else if (wcschr(source, _T(' '))) {
- // Needs to be quoted
- nQuotationMode = QUOTATION_DO;
- *target = _T('\"');
- ++j;
- } else {
- // No reason to quote term because it doesn't have embedded spaces
- nQuotationMode = QUOTATION_NONE;
- }
-
- for (; i < cpyLength; ++i, ++j) {
- if (source[i] == _T('\\')) {
- bSlash = true;
- } else {
- // Don't escape embracing quotation marks
- if ((source[i] == _T('\"')) &&
- !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))))) {
- if (!bSlash) { // If still not escaped
- if (j == availSpace) {
- return -1;
- }
- target[j] = _T('\\');
- ++j;
- }
- }
- bSlash = false;
- }
-
- if (j == availSpace) {
- return -1;
- }
- target[j] = source[i];
- }
-
- if (nQuotationMode == QUOTATION_DO) {
- if (j == availSpace) {
- return -1;
- }
- target[j] = _T('\"');
- ++j;
- }
-
- return j;
-}
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/starter.c b/core/org.eclipse.cdt.core.native/native_src/win/starter.c
index 85a9748813d..1622f3a0cda 100644
--- a/core/org.eclipse.cdt.core.native/native_src/win/starter.c
+++ b/core/org.eclipse.cdt.core.native/native_src/win/starter.c
@@ -120,67 +120,142 @@ bool runCygwinCommand(wchar_t *command) {
return false;
}
-void ensureSize(wchar_t **ptr, int *psize, int requiredLength) {
- int size = *psize;
- if (requiredLength > size) {
- size = 2 * size;
- if (size < requiredLength) {
- size = requiredLength;
+static bool openNamedPipeAsStdHandle(HANDLE *handle, DWORD stdHandle, int parentPid, int counter,
+ SECURITY_ATTRIBUTES *sa) {
+ wchar_t pipeName[PIPE_NAME_LENGTH];
+ DWORD dwDesiredAccess;
+ DWORD dwShareMode;
+
+ switch (stdHandle) {
+ case STD_INPUT_HANDLE:
+ BUILD_PIPE_NAME(pipeName, L"stdin", parentPid, counter);
+ dwDesiredAccess = GENERIC_READ;
+ dwShareMode = FILE_SHARE_READ;
+ break;
+ case STD_OUTPUT_HANDLE:
+ BUILD_PIPE_NAME(pipeName, L"stdout", parentPid, counter);
+ dwDesiredAccess = GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_WRITE;
+ break;
+ case STD_ERROR_HANDLE:
+ BUILD_PIPE_NAME(pipeName, L"stderr", parentPid, counter);
+ dwDesiredAccess = GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_WRITE;
+ break;
+ default:
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Invalid STD handle given %i", stdHandle);
}
- *ptr = (wchar_t *)realloc(*ptr, size * sizeof(wchar_t));
- if (*ptr) {
- *psize = size;
- } else {
- *psize = 0;
+ return false;
+ }
+
+ *handle = CreateFileW(pipeName, dwDesiredAccess, dwShareMode, NULL, OPEN_EXISTING, 0, sa);
+ if (INVALID_HANDLE_VALUE == *handle) {
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Failed to open pipe: %s -> %p\n", pipeName, handle);
}
+ return false;
}
-}
-int main() {
+ SetHandleInformation(*handle, HANDLE_FLAG_INHERIT, TRUE);
- int argc;
- wchar_t **argv = CommandLineToArgvW(GetCommandLine(), &argc);
+ if (!SetStdHandle(stdHandle, *handle)) {
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Failed to reassign standard stream to pipe %s: %i\n", pipeName, GetLastError());
+ }
+ return false;
+ }
- // Make sure that we've been passed the right number of arguments
- if (argc < 8) {
- wprintf(L"Usage: %s (four inheritable event handles) (CommandLineToSpawn)\n", argv[0]);
- return 0;
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Successfully assigned pipe %s -> %p\n", pipeName, *handle);
}
- // Construct the full command line
- int nCmdLineLength = MAX_CMD_LINE_LENGTH;
- wchar_t *szCmdLine = (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
- szCmdLine[0] = 0;
- int nPos = 0;
+ return true;
+}
- for (int i = 8; i < argc; ++i) {
- int nCpyLen;
- int len = wcslen(argv[i]);
- int requiredSize = nPos + len + 2;
- if (requiredSize > 32 * 1024) {
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Command line too long!\n");
+bool createCommandLine(int argc, wchar_t **argv, wchar_t **cmdLine) {
+ int size = MAX_CMD_LINE_LENGTH;
+ wchar_t *buffer = (wchar_t *)malloc(size * sizeof(wchar_t));
+
+ if (!buffer) {
+ // malloc failed
+ cdtTrace(L"Not enough memory to build cmd line!\n");
+ return false;
+ }
+
+ int nPos = 0;
+ for (int i = 0; i < argc; ++i) {
+ wchar_t *str = *(argv + i);
+ int len = wcslen(str);
+ if (str) {
+ int required = nPos + len + 2; // 2 => space + \0
+ if (required > 32 * 1024) {
+ free(buffer);
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Command line too long!\n");
+ }
+ return false;
}
- return 0;
- }
- ensureSize(&szCmdLine, &nCmdLineLength, requiredSize);
- if (!szCmdLine) {
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Not enough memory to build cmd line!\n");
+
+ while (1) {
+ // Ensure enough space in buffer
+ if (required > size) {
+ size *= 2;
+ if (size < required) {
+ size = required;
+ }
+
+ wchar_t *tmp = (wchar_t *)realloc(buffer, size * sizeof(wchar_t));
+ if (tmp) {
+ // realloc successful
+ buffer = tmp;
+ } else {
+ // Failed to realloc memory
+ free(buffer);
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Not enough memory to build cmd line!\n");
+ }
+ return false;
+ }
+ }
+
+ int nCpyLen = copyTo(buffer + nPos, (const wchar_t *)str, len, size - nPos);
+ if (nCpyLen < 0) { // Buffer too small
+ // Do a real count of number of chars required
+ required = nPos + copyTo(NULL, (const wchar_t *)str, len, INT_MAX) + 2; // 2 => space + \0
+ continue;
+ }
+
+ // Buffer was big enough.
+ nPos += nCpyLen;
+ break;
}
- return 0;
- }
- if (0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], len, nCmdLineLength - nPos))) {
+
+ buffer[nPos++] = _T(' ');
+ buffer[nPos] = _T('\0');
+ } else {
+ free(buffer);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Not enough space to build command line\n");
+ cdtTrace(L"Invalid argument!\n");
}
- return 0;
+ return false;
}
- nPos += nCpyLen;
- szCmdLine[nPos] = _T(' ');
- ++nPos;
}
- szCmdLine[nPos] = _T('\0');
+
+ *cmdLine = buffer;
+ return true;
+}
+
+int main() {
+
+ int argc;
+ wchar_t **argv = CommandLineToArgvW(GetCommandLine(), &argc);
+
+ // Make sure that we've been passed the right number of arguments
+ if (argc < 8) {
+ wprintf(L"Usage: %s (parent pid) (counter) (four inheritable event handles) (CommandLineToSpawn)\n", argv[0]);
+ return 0;
+ }
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
@@ -199,56 +274,22 @@ int main() {
int parentPid = wcstol(argv[1], NULL, 10);
int nCounter = wcstol(argv[2], NULL, 10);
- wchar_t inPipeName[PIPE_NAME_LENGTH];
- wchar_t outPipeName[PIPE_NAME_LENGTH];
- wchar_t errPipeName[PIPE_NAME_LENGTH];
-
- swprintf(inPipeName, sizeof(inPipeName) / sizeof(inPipeName[0]), L"\\\\.\\pipe\\stdin%08i%010i", parentPid,
- nCounter);
- swprintf(outPipeName, sizeof(outPipeName) / sizeof(outPipeName[0]), L"\\\\.\\pipe\\stdout%08i%010i", parentPid,
- nCounter);
- swprintf(errPipeName, sizeof(errPipeName) / sizeof(errPipeName[0]), L"\\\\.\\pipe\\stderr%08i%010i", parentPid,
- nCounter);
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Pipes: %s, %s, %s\n", inPipeName, outPipeName, errPipeName);
- }
- HANDLE stdHandles[3];
+ HANDLE stdHandles[] = {
+ INVALID_HANDLE_VALUE, // STDIN
+ INVALID_HANDLE_VALUE, // STDOUT
+ INVALID_HANDLE_VALUE // STDERR
+ };
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
- if ((INVALID_HANDLE_VALUE ==
- (stdHandles[0] = CreateFileW(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
- (INVALID_HANDLE_VALUE ==
- (stdHandles[1] = CreateFileW(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
- (INVALID_HANDLE_VALUE ==
- (stdHandles[2] = CreateFileW(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa)))) {
-
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Failed to open pipe %i, %i, %i: %i\n", stdHandles[0], stdHandles[1], stdHandles[2],
- GetLastError());
- }
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
- return -1;
- }
- SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE);
- SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE);
- SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE);
-
- if (!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) || !SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) ||
- !SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) {
-
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Failed to reassign standard streams: %i\n", GetLastError());
- }
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
+ if (!openNamedPipeAsStdHandle(&stdHandles[0], STD_INPUT_HANDLE, parentPid, nCounter, &sa) ||
+ !openNamedPipeAsStdHandle(&stdHandles[1], STD_OUTPUT_HANDLE, parentPid, nCounter, &sa) ||
+ !openNamedPipeAsStdHandle(&stdHandles[2], STD_ERROR_HANDLE, parentPid, nCounter, &sa)) {
+ CLOSE_HANDLES(stdHandles);
return -1;
}
@@ -270,9 +311,7 @@ int main() {
cdtTrace(L"Cannot Read Environment\n");
}
}
- if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Starting: %s\n", szCmdLine);
- }
+
// Create job object
HANDLE hJob = CreateJobObject(NULL, NULL);
if (hJob) {
@@ -292,22 +331,34 @@ int main() {
cdtTrace(L"Cannot create job object\n");
DisplayErrorMessage();
}
+
+ // Construct the full command line
+ wchar_t *cmdLine = NULL;
+ if (!createCommandLine(argc - 8, &argv[8], &cmdLine)) {
+ return 0;
+ }
+
+ if (isTraceEnabled(CDT_TRACE_MONITOR)) {
+ cdtTrace(L"Starting: %s\n", cmdLine);
+ }
+
// Spawn the other processes as part of this Process Group
// If this process is already part of a job, the flag CREATE_BREAKAWAY_FROM_JOB
// makes the child process detach from the job, such that we can assign it
// to our own job object.
- BOOL f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
+ BOOL f = CreateProcessW(NULL, cmdLine, NULL, NULL, TRUE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, &si, &pi);
// If breaking away from job is not permitted, retry without breakaway flag
if (!f) {
- f = CreateProcessW(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
+ f = CreateProcessW(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
}
// We don't need them any more
- CloseHandle(stdHandles[0]);
- CloseHandle(stdHandles[1]);
- CloseHandle(stdHandles[2]);
+ CLOSE_HANDLES(stdHandles);
if (f) {
+ free(cmdLine);
+ cmdLine = NULL;
+
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Process %i started\n", pi.dwProcessId);
}
@@ -406,91 +457,18 @@ int main() {
}
}
} else if (isTraceEnabled(CDT_TRACE_MONITOR)) {
- cdtTrace(L"Cannot start: %s\n", szCmdLine);
+ cdtTrace(L"Cannot start: %s\n", cmdLine);
+ free(cmdLine);
DisplayErrorMessage();
}
- free(szCmdLine);
-
CloseHandle(waitEvent);
- CloseHandle(h[0]);
- CloseHandle(h[1]);
- CloseHandle(h[2]);
- CloseHandle(h[3]);
- CloseHandle(h[4]);
+ CLOSE_HANDLES(h);
return dwExitCode;
}
-/////////////////////////////////////////////////////////////////////////////////////
-// Use this utility program to process correctly quotation marks in the command line
-// Arguments:
-// target - string to copy to
-// source - string to copy from
-// cpyLength - copy length
-// availSpace - size of the target buffer
-// Return :number of bytes used in target, or -1 in case of error
-/////////////////////////////////////////////////////////////////////////////////////
-int copyTo(wchar_t *target, const wchar_t *source, int cpyLength, int availSpace) {
- bool bSlash = false;
- int i = 0, j = 0;
-
- enum { QUOTATION_DO, QUOTATION_DONE, QUOTATION_NONE } nQuotationMode = QUOTATION_DO;
-
- if (availSpace <= cpyLength) { // = to reserve space for '\0'
- return -1;
- }
-
- if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
- // Already done
- nQuotationMode = QUOTATION_DONE;
- } else if (wcschr(source, _T(' '))) {
- // Needs to be quotated
- nQuotationMode = QUOTATION_DO;
- *target = _T('\"');
- ++j;
- } else {
- // No reason to quotate term because it doesn't have embedded spaces
- nQuotationMode = QUOTATION_NONE;
- }
-
- for (; i < cpyLength; ++i, ++j) {
- if (source[i] == _T('\\')) {
- bSlash = true;
- } else {
- // Don't escape embracing quotation marks
- if ((source[i] == _T('\"')) &&
- !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))))) {
- if (!bSlash) {
- if (j == availSpace) {
- return -1;
- }
- target[j] = _T('\\');
- ++j;
- }
- bSlash = false;
- } else {
- bSlash = false;
- }
- }
-
- if (j == availSpace) {
- return -1;
- }
- target[j] = source[i];
- }
-
- if (nQuotationMode == QUOTATION_DO) {
- if (j == availSpace) {
- return -1;
- }
- target[j] = _T('\"');
- ++j;
- }
- return j;
-}
-
void DisplayErrorMessage() {
wchar_t *lpMsgBuf;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/util.c b/core/org.eclipse.cdt.core.native/native_src/win/util.c
index 3191751c972..46b6c90b051 100644
--- a/core/org.eclipse.cdt.core.native/native_src/win/util.c
+++ b/core/org.eclipse.cdt.core.native/native_src/win/util.c
@@ -15,6 +15,7 @@
#include "util.h"
#include <stdio.h>
+#include <tchar.h>
bool isTraceEnabled(const TraceKind_t traceKind) {
static bool initialized = false;
@@ -73,3 +74,66 @@ void cdtTrace(const wchar_t *fmt, ...) {
// Clean up
free(buffer);
}
+
+int copyTo(wchar_t *target, const wchar_t *source, int cpyLength, int availSpace) {
+ bool bSlash = false;
+ int i = 0, j = 0;
+
+ enum { QUOTATION_DO, QUOTATION_DONE, QUOTATION_NONE } nQuotationMode = QUOTATION_DO;
+
+ if (availSpace <= cpyLength) { // = to reserve space for final '\0'
+ return -1;
+ }
+
+ if ((_T('\"') == *source) && (_T('\"') == *(source + cpyLength - 1))) {
+ nQuotationMode = QUOTATION_DONE;
+ } else if (wcschr(source, _T(' '))) {
+ // Needs to be quoted
+ nQuotationMode = QUOTATION_DO;
+ if (target) {
+ *target = _T('\"');
+ }
+ ++j;
+ } else {
+ // No reason to quote term because it doesn't have embedded spaces
+ nQuotationMode = QUOTATION_NONE;
+ }
+
+ for (; i < cpyLength; ++i, ++j) {
+ if (source[i] == _T('\\')) {
+ bSlash = true;
+ } else {
+ // Don't escape embracing quotation marks
+ if ((source[i] == _T('\"')) &&
+ !((nQuotationMode == QUOTATION_DONE) && ((i == 0) || (i == (cpyLength - 1))))) {
+ if (!bSlash) { // If still not escaped
+ if (j == availSpace) {
+ return -1;
+ }
+ target[j] = _T('\\');
+ ++j;
+ }
+ }
+ bSlash = false;
+ }
+
+ if (j == availSpace) {
+ return -1;
+ }
+ if (target) {
+ target[j] = source[i];
+ }
+ }
+
+ if (nQuotationMode == QUOTATION_DO) {
+ if (j == availSpace) {
+ return -1;
+ }
+ if (target) {
+ target[j] = _T('\"');
+ }
+ ++j;
+ }
+
+ return j;
+}
diff --git a/core/org.eclipse.cdt.core.native/native_src/win/util.h b/core/org.eclipse.cdt.core.native/native_src/win/util.h
index d5991da771b..56a43460bdb 100644
--- a/core/org.eclipse.cdt.core.native/native_src/win/util.h
+++ b/core/org.eclipse.cdt.core.native/native_src/win/util.h
@@ -23,4 +23,21 @@ typedef enum { CDT_TRACE_MONITOR, CDT_TRACE_MONITOR_DETAILS, CDT_TRACE_READ_REPO
bool isTraceEnabled(const TraceKind_t traceKind);
void cdtTrace(const wchar_t *fmt, ...);
+#define BUILD_PIPE_NAME(pipe, name, pid, counter) \
+ do { \
+ swprintf(pipe, sizeof(pipe) / sizeof(pipe[0]), L"\\\\.\\pipe\\%s%08i%010i", name, pid, counter); \
+ } while (0)
+
+#define CLOSE_HANDLES(handles) \
+ do { \
+ for (int i = 0; i < sizeof(handles) / sizeof(handles[0]); i++) { \
+ if (INVALID_HANDLE_VALUE != handles[i]) { \
+ CloseHandle(handles[i]); \
+ handles[i] = INVALID_HANDLE_VALUE; \
+ } \
+ } \
+ } while (0)
+
+int copyTo(wchar_t *target, const wchar_t *source, int cpyLength, int availSpace);
+
#endif /* UTIL_H */
diff --git a/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/pty.dll b/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/pty.dll
index 5751bb16ad0..21a533ee5c1 100755
--- a/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/pty.dll
+++ b/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/pty.dll
Binary files differ
diff --git a/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/spawner.dll b/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/spawner.dll
index ae55557671a..d73a80aadef 100755
--- a/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/spawner.dll
+++ b/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/spawner.dll
Binary files differ
diff --git a/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/starter.exe b/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/starter.exe
index d86256e27d1..2a1bc90e617 100755
--- a/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/starter.exe
+++ b/core/org.eclipse.cdt.core.win32.x86_64/os/win32/x86_64/starter.exe
Binary files differ

Back to the top