zturner created this revision.
zturner added a reviewer: amccarth.
zturner added a subscriber: lldb-commits.

    There were a number of problems preventing this from working:

    1. The SWIG typemaps for converting Python lists to and from C++
       arrays were not updated for Python 3.  So they were doing things
       like PyString_Check instead of using the PythonString from
       PythonDataObjects.
    2. ProcessLauncherWindows was ignoring the environment completely.
       So any test that involved launching an inferior with any kind
       of environment variable would have failed.
    3. The test itself was using process.GetSTDOUT(), which isn't
       implemented on Windows.  So this was changed to redirect
       stdout to a file, and then the test reads the file.

http://reviews.llvm.org/D16128

Files:
  
packages/Python/lldbsuite/test/functionalities/process_launch/TestProcessLaunch.py
  packages/Python/lldbsuite/test/functionalities/process_launch/print_env.cpp
  scripts/Python/python-typemaps.swig
  source/Host/windows/ProcessLauncherWindows.cpp

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<char> &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<Args &>(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<char *>(commandLine.c_str()), NULL, NULL, TRUE, flags, NULL,
-                                   launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi);
+    BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(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.
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<PythonString>();
+      if (!py_str.IsAllocated()) {
         PyErr_SetString(PyExc_TypeError,"list must contain strings");
         free($1);
-        return NULL;
+        return nullptr;
       }
+
+      $1[i] = const_cast<char*>(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<PythonString>();
+      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<PythonString>();
+      if (!py_str.IsAllocated()) {
         PyErr_SetString(PyExc_TypeError,"list must contain strings");
         free($1);
         return nullptr;
       }
-      auto py_str = o.AsType<PythonString>();
       $1[i] = const_cast<char*>(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<PythonString>();
+      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: 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: 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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to