Skip to content

Commit b07823f

Browse files
update ScriptInterpreterPython to use File, not FILE*
Summary: ScriptInterpreterPython needs to save and restore sys.stdout and friends when LLDB runs a python script. It currently does this using FILE*, which is not optimal. If whatever was in sys.stdout can not be represented as a FILE*, then it will not be restored correctly when the script is finished. It also means that if the debugger's own output stream is not representable as a file, ScriptInterpreterPython will not be able to redirect python's output correctly. This patch updates ScriptInterpreterPython to represent files with lldb_private::File, and to represent whatever the user had in sys.stdout as simply a PythonObject. This will make lldb interoperate better with other scripts or programs that need to manipulate sys.stdout. Reviewers: JDevlieghere, jasonmolenda, labath Reviewed By: labath Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D68962 llvm-svn: 374964
1 parent 9d10b9d commit b07823f

File tree

4 files changed

+56
-64
lines changed

4 files changed

+56
-64
lines changed

lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,9 +445,8 @@ def test_fileno_error(self):
445445
self.assertTrue(re.search(r'error:.*lolwut', errors))
446446
self.assertTrue(re.search(r'zork', errors))
447447

448-
#FIXME This shouldn't fail for python2 either.
448+
449449
@add_test_categories(['pyapi'])
450-
@skipIf(py_version=['<', (3,)])
451450
def test_replace_stdout(self):
452451
f = io.StringIO()
453452
with replace_stdout(f):
@@ -458,7 +457,6 @@ def test_replace_stdout(self):
458457

459458

460459
@add_test_categories(['pyapi'])
461-
@expectedFailureAll() #FIXME bug in ScriptInterpreterPython
462460
def test_replace_stdout_with_nonfile(self):
463461
debugger = self.debugger
464462
f = io.StringIO()

lldb/source/Core/Debugger.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -973,34 +973,31 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
973973
std::lock_guard<std::recursive_mutex> guard(m_input_reader_stack.GetMutex());
974974
IOHandlerSP top_reader_sp(m_input_reader_stack.Top());
975975
// If no STDIN has been set, then set it appropriately
976-
if (!in) {
976+
if (!in || !in->IsValid()) {
977977
if (top_reader_sp)
978978
in = top_reader_sp->GetInputFileSP();
979979
else
980980
in = GetInputFileSP();
981-
982981
// If there is nothing, use stdin
983982
if (!in)
984983
in = std::make_shared<NativeFile>(stdin, false);
985984
}
986985
// If no STDOUT has been set, then set it appropriately
987-
if (!out) {
986+
if (!out || !out->GetFile().IsValid()) {
988987
if (top_reader_sp)
989988
out = top_reader_sp->GetOutputStreamFileSP();
990989
else
991990
out = GetOutputStreamSP();
992-
993991
// If there is nothing, use stdout
994992
if (!out)
995993
out = std::make_shared<StreamFile>(stdout, false);
996994
}
997995
// If no STDERR has been set, then set it appropriately
998-
if (!err) {
996+
if (!err || !err->GetFile().IsValid()) {
999997
if (top_reader_sp)
1000998
err = top_reader_sp->GetErrorStreamFileSP();
1001999
else
10021000
err = GetErrorStreamSP();
1003-
10041001
// If there is nothing, use stderr
10051002
if (!err)
10061003
err = std::make_shared<StreamFile>(stderr, false);

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ void ScriptInterpreterPython::Terminate() {}
370370

371371
ScriptInterpreterPythonImpl::Locker::Locker(
372372
ScriptInterpreterPythonImpl *py_interpreter, uint16_t on_entry,
373-
uint16_t on_leave, FILE *in, FILE *out, FILE *err)
373+
uint16_t on_leave, FileSP in, FileSP out, FileSP err)
374374
: ScriptInterpreterLocker(),
375375
m_teardown_session((on_leave & TearDownSession) == TearDownSession),
376376
m_python_interpreter(py_interpreter) {
@@ -400,8 +400,8 @@ bool ScriptInterpreterPythonImpl::Locker::DoAcquireLock() {
400400
}
401401

402402
bool ScriptInterpreterPythonImpl::Locker::DoInitSession(uint16_t on_entry_flags,
403-
FILE *in, FILE *out,
404-
FILE *err) {
403+
FileSP in, FileSP out,
404+
FileSP err) {
405405
if (!m_python_interpreter)
406406
return false;
407407
return m_python_interpreter->EnterSession(on_entry_flags, in, out, err);
@@ -636,28 +636,31 @@ void ScriptInterpreterPythonImpl::LeaveSession() {
636636
m_session_is_active = false;
637637
}
638638

639-
bool ScriptInterpreterPythonImpl::SetStdHandle(File &file, const char *py_name,
640-
PythonFile &save_file,
639+
bool ScriptInterpreterPythonImpl::SetStdHandle(FileSP file_sp,
640+
const char *py_name,
641+
PythonObject &save_file,
641642
const char *mode) {
642-
if (file.IsValid()) {
643-
// Flush the file before giving it to python to avoid interleaved output.
644-
file.Flush();
643+
if (!file_sp || !*file_sp) {
644+
save_file.Reset();
645+
return false;
646+
}
647+
File &file = *file_sp;
645648

646-
PythonDictionary &sys_module_dict = GetSysModuleDictionary();
649+
// Flush the file before giving it to python to avoid interleaved output.
650+
file.Flush();
647651

648-
save_file = sys_module_dict.GetItemForKey(PythonString(py_name))
649-
.AsType<PythonFile>();
652+
PythonDictionary &sys_module_dict = GetSysModuleDictionary();
650653

651-
PythonFile new_file(file, mode);
652-
sys_module_dict.SetItemForKey(PythonString(py_name), new_file);
653-
return true;
654-
} else
655-
save_file.Reset();
656-
return false;
654+
save_file = sys_module_dict.GetItemForKey(PythonString(py_name));
655+
656+
PythonFile new_file(file, mode);
657+
sys_module_dict.SetItemForKey(PythonString(py_name), new_file);
658+
return true;
657659
}
658660

659661
bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags,
660-
FILE *in, FILE *out, FILE *err) {
662+
FileSP in_sp, FileSP out_sp,
663+
FileSP err_sp) {
661664
// If we have already entered the session, without having officially 'left'
662665
// it, then there is no need to 'enter' it again.
663666
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SCRIPT));
@@ -706,33 +709,29 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags,
706709

707710
PythonDictionary &sys_module_dict = GetSysModuleDictionary();
708711
if (sys_module_dict.IsValid()) {
709-
NativeFile in_file(in, false);
710-
NativeFile out_file(out, false);
711-
NativeFile err_file(err, false);
712-
713-
lldb::FileSP in_sp;
714-
lldb::StreamFileSP out_sp;
715-
lldb::StreamFileSP err_sp;
716-
if (!in_file.IsValid() || !out_file.IsValid() || !err_file.IsValid())
717-
m_debugger.AdoptTopIOHandlerFilesIfInvalid(in_sp, out_sp, err_sp);
712+
lldb::FileSP top_in_sp;
713+
lldb::StreamFileSP top_out_sp, top_err_sp;
714+
if (!in_sp || !out_sp || !err_sp || !*in_sp || !*out_sp || !*err_sp)
715+
m_debugger.AdoptTopIOHandlerFilesIfInvalid(top_in_sp, top_out_sp,
716+
top_err_sp);
718717

719718
if (on_entry_flags & Locker::NoSTDIN) {
720719
m_saved_stdin.Reset();
721720
} else {
722-
if (!SetStdHandle(in_file, "stdin", m_saved_stdin, "r")) {
723-
if (in_sp)
724-
SetStdHandle(*in_sp, "stdin", m_saved_stdin, "r");
721+
if (!SetStdHandle(in_sp, "stdin", m_saved_stdin, "r")) {
722+
if (top_in_sp)
723+
SetStdHandle(top_in_sp, "stdin", m_saved_stdin, "r");
725724
}
726725
}
727726

728-
if (!SetStdHandle(out_file, "stdout", m_saved_stdout, "w")) {
729-
if (out_sp)
730-
SetStdHandle(out_sp->GetFile(), "stdout", m_saved_stdout, "w");
727+
if (!SetStdHandle(out_sp, "stdout", m_saved_stdout, "w")) {
728+
if (top_out_sp)
729+
SetStdHandle(top_out_sp->GetFileSP(), "stdout", m_saved_stdout, "w");
731730
}
732731

733-
if (!SetStdHandle(err_file, "stderr", m_saved_stderr, "w")) {
734-
if (err_sp)
735-
SetStdHandle(err_sp->GetFile(), "stderr", m_saved_stderr, "w");
732+
if (!SetStdHandle(err_sp, "stderr", m_saved_stderr, "w")) {
733+
if (top_err_sp)
734+
SetStdHandle(top_err_sp->GetFileSP(), "stderr", m_saved_stderr, "w");
736735
}
737736
}
738737

@@ -909,9 +908,6 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
909908
error_file_sp = output_file_sp = std::make_shared<StreamFile>(std::move(nullout.get()));
910909
}
911910

912-
FILE *in_file = input_file_sp->GetStream();
913-
FILE *out_file = output_file_sp->GetFile().GetStream();
914-
FILE *err_file = error_file_sp->GetFile().GetStream();
915911
bool success = false;
916912
{
917913
// WARNING! It's imperative that this RAII scope be as tight as
@@ -927,8 +923,8 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
927923
Locker::AcquireLock | Locker::InitSession |
928924
(options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) |
929925
((result && result->GetInteractive()) ? 0 : Locker::NoSTDIN),
930-
Locker::FreeAcquiredLock | Locker::TearDownSession, in_file, out_file,
931-
err_file);
926+
Locker::FreeAcquiredLock | Locker::TearDownSession, input_file_sp,
927+
output_file_sp->GetFileSP(), error_file_sp->GetFileSP());
932928

933929
// Find the correct script interpreter dictionary in the main module.
934930
PythonDictionary &session_dict = GetSessionDictionary();
@@ -955,9 +951,8 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine(
955951
}
956952

957953
// Flush our output and error file handles
958-
::fflush(out_file);
959-
if (out_file != err_file)
960-
::fflush(err_file);
954+
output_file_sp->Flush();
955+
error_file_sp->Flush();
961956
}
962957

963958
if (join_read_thread) {

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -294,25 +294,26 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
294294
TearDownSession = 0x0004
295295
};
296296

297-
Locker(ScriptInterpreterPythonImpl *py_interpreter = nullptr,
297+
Locker(ScriptInterpreterPythonImpl *py_interpreter,
298298
uint16_t on_entry = AcquireLock | InitSession,
299-
uint16_t on_leave = FreeLock | TearDownSession, FILE *in = nullptr,
300-
FILE *out = nullptr, FILE *err = nullptr);
299+
uint16_t on_leave = FreeLock | TearDownSession,
300+
lldb::FileSP in = nullptr, lldb::FileSP out = nullptr,
301+
lldb::FileSP err = nullptr);
301302

302303
~Locker() override;
303304

304305
private:
305306
bool DoAcquireLock();
306307

307-
bool DoInitSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err);
308+
bool DoInitSession(uint16_t on_entry_flags, lldb::FileSP in,
309+
lldb::FileSP out, lldb::FileSP err);
308310

309311
bool DoFreeLock();
310312

311313
bool DoTearDownSession();
312314

313315
bool m_teardown_session;
314316
ScriptInterpreterPythonImpl *m_python_interpreter;
315-
// FILE* m_tmp_fh;
316317
PyGILState_STATE m_GILState;
317318
};
318319

@@ -341,7 +342,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
341342

342343
static void AddToSysPath(AddLocation location, std::string path);
343344

344-
bool EnterSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err);
345+
bool EnterSession(uint16_t on_entry_flags, lldb::FileSP in, lldb::FileSP out,
346+
lldb::FileSP err);
345347

346348
void LeaveSession();
347349

@@ -369,12 +371,12 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
369371

370372
bool GetEmbeddedInterpreterModuleObjects();
371373

372-
bool SetStdHandle(File &file, const char *py_name, PythonFile &save_file,
373-
const char *mode);
374+
bool SetStdHandle(lldb::FileSP file, const char *py_name,
375+
PythonObject &save_file, const char *mode);
374376

375-
PythonFile m_saved_stdin;
376-
PythonFile m_saved_stdout;
377-
PythonFile m_saved_stderr;
377+
PythonObject m_saved_stdin;
378+
PythonObject m_saved_stdout;
379+
PythonObject m_saved_stderr;
378380
PythonObject m_main_module;
379381
PythonDictionary m_session_dict;
380382
PythonDictionary m_sys_module_dict;

0 commit comments

Comments
 (0)