Fix TestProcessLaunch for Python 3.

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 save the
   value of the environment variable in a local variable and
   have the debugger look at the value of the variable.

llvm-svn: 257669
This commit is contained in:
Zachary Turner 2016-01-13 21:21:49 +00:00
parent a4976b33d2
commit 19e2ea8fb6
4 changed files with 95 additions and 44 deletions

View File

@ -4,12 +4,15 @@ Test lldb process launch flags.
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 @@ class ProcessLaunchTestCase(TestBase):
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):
@ -180,8 +192,9 @@ class ProcessLaunchTestCase(TestBase):
self.fail(err_msg)
def test_environment_with_special_char (self):
"""Test that environment variables containing '*' and '}' are communicated correctly to the lldb-server."""
d = {'CXX_SOURCES' : 'print_env.cpp'}
"""Test that environment variables containing '*' and '}' are handled correctly by the inferior."""
source = 'print_env.cpp'
d = {'CXX_SOURCES' : source}
self.build(dictionary=d)
self.setTearDownCleanup(d)
exe = os.path.join (os.getcwd(), "a.out")
@ -189,19 +202,19 @@ class ProcessLaunchTestCase(TestBase):
evil_var = 'INIT*MIDDLE}TAIL'
target = self.dbg.CreateTarget(exe)
main_source_spec = lldb.SBFileSpec(source)
breakpoint = target.BreakpointCreateBySourceRegex('// Set breakpoint here.', main_source_spec)
process = target.LaunchSimple(None, ['EVIL=' + evil_var], self.get_process_working_directory())
self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint)
self.assertEqual(len(threads), 1)
frame = threads[0].GetFrameAtIndex(0)
sbvalue = frame.EvaluateExpression("evil")
value = sbvalue.GetSummary().strip('"')
self.assertEqual(value, evil_var)
process.Continue()
self.assertEqual(process.GetState(), lldb.eStateExited, PROCESS_EXITED)
out = process.GetSTDOUT(len(evil_var))
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')
pass

View File

@ -5,7 +5,6 @@
int main (int argc, char **argv)
{
char *evil = getenv("EVIL");
puts(evil);
return 0;
return 0; // Set breakpoint here.
}

View File

@ -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. */

View File

@ -17,6 +17,31 @@
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);
}
// Environment buffer is a null terminated list of null terminated
// strings, so it is terminated by two null bytes.
buffer.back() = 0;
}
}
HostProcess
ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
{
@ -49,10 +74,16 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Erro
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.