forked from OSchip/llvm-project
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:
parent
a4976b33d2
commit
19e2ea8fb6
|
@ -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
|
|
@ -5,7 +5,6 @@
|
|||
int main (int argc, char **argv)
|
||||
{
|
||||
char *evil = getenv("EVIL");
|
||||
puts(evil);
|
||||
|
||||
return 0;
|
||||
return 0; // Set breakpoint here.
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue