Index: packages/Python/lldbsuite/test/functionalities/process_launch/TestProcessLaunch.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/process_launch/TestProcessLaunch.py +++ packages/Python/lldbsuite/test/functionalities/process_launch/TestProcessLaunch.py @@ -4,12 +4,15 @@ from __future__ import print_function +import copy +import os +import time - -import os, time import lldb from lldbsuite.test.lldbtest import * +import six + class ProcessLaunchTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -17,9 +20,18 @@ def setUp(self): # Call super's setUp(). TestBase.setUp(self) + self.stdout_redirect_file = 'lldb-stdout-redirect.txt' # disable "There is a running process, kill it and restart?" prompt self.runCmd("settings set auto-confirm true") - self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm")) + def tearDown(self): + self.runCmd("settings clear auto-confirm") + + try: + os.unlink(self.stdout_redirect_file) + except: + pass + + super().tearDown() @not_remote_testsuite_ready def test_io (self): @@ -188,20 +200,27 @@ evil_var = 'INIT*MIDDLE}TAIL' - target = self.dbg.CreateTarget(exe) - process = target.LaunchSimple(None, ['EVIL=' + evil_var], self.get_process_working_directory()) - self.assertEqual(process.GetState(), lldb.eStateExited, PROCESS_EXITED) + error = lldb.SBError() - out = process.GetSTDOUT(len(evil_var)) + target = self.dbg.CreateTarget(exe) + launch_info = lldb.SBLaunchInfo([]) + launch_info.SetWorkingDirectory(self.get_process_working_directory()) + environment = dict(os.environ) + environment['EVIL'] = evil_var + environment = [x + "=" + y for (x, y) in six.iteritems(environment)] + + launch_info.SetEnvironmentEntries(environment, True) + launch_info.AddOpenFileAction(1, self.stdout_redirect_file, False, True) + process = target.Launch(launch_info, error) + + state = process.GetState() + self.assertEqual(state, lldb.eStateExited, PROCESS_EXITED) + + out = None + with open(self.stdout_redirect_file) as output: + out = output.read().rstrip() self.assertIsNotNone(out, "Encountered an error reading the process's output") - out = out[:len(evil_var)] if out != evil_var: self.fail('The environment variable was mis-coded: %s\n' % repr(out)) - - newline = process.GetSTDOUT(1) - self.assertIsNotNone(newline, "Encountered an error reading the process's output") - - newline = newline[0] - if newline != '\r' and newline != '\n': - self.fail('Garbage at end of environment variable') + \ No newline at end of file Index: packages/Python/lldbsuite/test/functionalities/process_launch/print_env.cpp =================================================================== --- packages/Python/lldbsuite/test/functionalities/process_launch/print_env.cpp +++ packages/Python/lldbsuite/test/functionalities/process_launch/print_env.cpp @@ -5,7 +5,10 @@ int main (int argc, char **argv) { char *evil = getenv("EVIL"); - puts(evil); + if (evil == nullptr) + printf("Environment variable EVIL is not set\n"); + else + puts(evil); return 0; } Index: scripts/Python/python-typemaps.swig =================================================================== --- scripts/Python/python-typemaps.swig +++ scripts/Python/python-typemaps.swig @@ -1,20 +1,22 @@ /* Typemap definitions, to allow SWIG to properly handle 'char**' data types. */ %typemap(in) char ** { + using namespace lldb_private; /* Check if is a list */ - if (PyList_Check($input)) { - int size = PyList_Size($input); + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); int i = 0; - $1 = (char **) malloc((size+1) * sizeof(char*)); + $1 = (char**)malloc((size+1)*sizeof(char*)); for (i = 0; i < size; i++) { - PyObject *o = PyList_GetItem($input,i); - if (PyString_Check(o)) - $1[i] = PyString_AsString(o); - else { + PythonString py_str = list.GetItemAtIndex(i).AsType(); + if (!py_str.IsAllocated()) { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($1); - return NULL; + return nullptr; } + + $1[i] = const_cast(py_str.GetString().data()); } $1[i] = 0; } else if ($input == Py_None) { @@ -42,12 +44,14 @@ %typemap(typecheck) char ** { /* Check if is a list */ $1 = 1; - if (PyList_Check($input)) { - int size = PyList_Size($input); + using namespace lldb_private; + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); int i = 0; for (i = 0; i < size; i++) { - PyObject *o = PyList_GetItem($input,i); - if (!PyString_Check(o)) { $1 = 0; } + PythonString s = list.GetItemAtIndex(i).AsType(); + if (!s.IsAllocated()) { $1 = 0; } } } else @@ -81,13 +85,12 @@ $1 = (char**)malloc((size+1)*sizeof(char*)); for (int i = 0; i < size; i++) { - PythonObject o = py_list.GetItemAtIndex(i); - if (!PythonString::Check(o.get())) { + auto py_str = py_list.GetItemAtIndex(i).AsType(); + if (!py_str.IsAllocated()) { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($1); return nullptr; } - auto py_str = o.AsType(); $1[i] = const_cast(py_str.GetString().data()); } @@ -101,14 +104,16 @@ } %typemap(typecheck) char const ** { + using namespace lldb_private; /* Check if is a list */ $1 = 1; - if (PyList_Check($input)) { - int size = PyList_Size($input); + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); int i = 0; for (i = 0; i < size; i++) { - PyObject *o = PyList_GetItem($input,i); - if (!PyString_Check(o)) { $1 = 0; } + PythonString s = list.GetItemAtIndex(i).AsType(); + if (!s.IsAllocated()) { $1 = 0; } } } else @@ -126,10 +131,13 @@ int i; len = 0; while ($1[len]) len++; - $result = PyList_New(len); + using namespace lldb_private; + PythonList list(len); for (i = 0; i < len; i++) { - PyList_SetItem($result, i, PyString_FromString($1[i])); + PythonString str($1[i]); + list.SetItemAtIndex(i, str); } + $result = list.release(); } /* Typemap definitions to allow SWIG to properly handle char buffer. */ Index: source/Host/windows/ProcessLauncherWindows.cpp =================================================================== --- source/Host/windows/ProcessLauncherWindows.cpp +++ source/Host/windows/ProcessLauncherWindows.cpp @@ -17,6 +17,28 @@ using namespace lldb; using namespace lldb_private; +namespace +{ +void +CreateEnvironmentBuffer(const Args &env, std::vector &buffer) +{ + if (env.GetArgumentCount() == 0) + return; + + int bytes = 0; + for (int i = 0; i < env.GetArgumentCount(); ++i) + bytes += strlen(env.GetArgumentAtIndex(i)) + sizeof(char); + bytes += sizeof(char); + buffer.resize(bytes); + char *cur_entry = &buffer[0]; + for (int i = 0; i < env.GetArgumentCount(); ++i) + { + ::strcpy(cur_entry, env.GetArgumentAtIndex(i)); + cur_entry += strlen(cur_entry) + sizeof(char); + } +} +} + HostProcess ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) { @@ -49,10 +71,16 @@ if (launch_info.GetFlags().Test(eLaunchFlagDebug)) flags |= DEBUG_ONLY_THIS_PROCESS; + auto &env = const_cast(launch_info.GetEnvironmentEntries()); + LPVOID env_block = nullptr; + ::CreateEnvironmentBuffer(env, environment); + if (!environment.empty()) + env_block = environment.data(); + executable = launch_info.GetExecutableFile().GetPath(); launch_info.GetArguments().GetQuotedCommandString(commandLine); - BOOL result = ::CreateProcessA(executable.c_str(), const_cast(commandLine.c_str()), NULL, NULL, TRUE, flags, NULL, - launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi); + BOOL result = ::CreateProcessA(executable.c_str(), const_cast(commandLine.c_str()), NULL, NULL, TRUE, flags, + env_block, launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi); if (result) { // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess.