Introduce a PythonExceptionState class.

This is a helper class which supports a number of
features including exception to string formatting with
backtrace handling and auto-restore of exception state
upon scope exit.

Additionally, unit tests are included to verify the
feature set of the class.

llvm-svn: 252994
This commit is contained in:
Zachary Turner
2015-11-13 01:24:52 +00:00
parent c946d46283
commit 3946247caf
6 changed files with 385 additions and 85 deletions

View File

@@ -16,6 +16,7 @@
#include "lldb-python.h"
#include "ScriptInterpreterPython.h"
#include "PythonDataObjects.h"
#include "PythonExceptionState.h"
#include <stdlib.h>
#include <stdio.h>
@@ -178,8 +179,6 @@ private:
}
static std::string ReadPythonBacktrace(PythonObject py_backtrace);
ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter,
uint16_t on_entry,
uint16_t on_leave,
@@ -1245,37 +1244,9 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
}
}
py_error.Reset(PyRefType::Borrowed, PyErr_Occurred());
if (py_error.IsValid())
{
// puts(in_string);
// _PyObject_Dump (py_error);
// PyErr_Print();
// success = false;
PyObject *py_type = nullptr;
PyObject *py_value = nullptr;
PyObject *py_traceback = nullptr;
PyErr_Fetch(&py_type, &py_value, &py_traceback);
PythonObject type(PyRefType::Owned, py_type);
PythonObject value(PyRefType::Owned, py_value);
PythonObject traceback(PyRefType::Owned, py_traceback);
// get the backtrace
std::string bt = ReadPythonBacktrace(traceback);
if (value.IsAllocated())
{
PythonString str = value.Str();
llvm::StringRef value_str(str.GetString());
error.SetErrorStringWithFormat("%s\n%s", value_str.str().c_str(), bt.c_str());
}
else
error.SetErrorStringWithFormat("%s",bt.c_str());
if (options.GetMaskoutErrors())
PyErr_Clear();
}
PythonExceptionState exception_state(!options.GetMaskoutErrors());
if (exception_state.IsError())
error.SetErrorString(exception_state.Format().c_str());
return error;
}
@@ -2377,58 +2348,6 @@ ScriptInterpreterPython::GetSyntheticValue(const StructuredData::ObjectSP &imple
return ret_val;
}
static std::string
ReadPythonBacktrace(PythonObject py_backtrace)
{
PythonObject traceback_module;
PythonObject stringIO_module;
PythonObject stringIO_builder;
PythonObject stringIO_buffer;
PythonObject printTB;
PythonObject printTB_args;
PythonObject printTB_result;
PythonObject stringIO_getvalue;
PythonObject printTB_string;
std::string retval("backtrace unavailable");
if (!py_backtrace.IsAllocated())
return retval;
traceback_module.Reset(PyRefType::Owned, PyImport_ImportModule("traceback"));
stringIO_module.Reset(PyRefType::Owned, PyImport_ImportModule("StringIO"));
if (!traceback_module.IsAllocated() || !stringIO_module.IsAllocated())
return retval;
stringIO_builder.Reset(PyRefType::Owned, PyObject_GetAttrString(stringIO_module.get(), "StringIO"));
if (!stringIO_builder.IsAllocated())
return retval;
stringIO_buffer.Reset(PyRefType::Owned, PyObject_CallObject(stringIO_builder.get(), nullptr));
if (!stringIO_buffer.IsAllocated())
return retval;
printTB.Reset(PyRefType::Owned, PyObject_GetAttrString(traceback_module.get(), "print_tb"));
if (!printTB.IsAllocated())
return retval;
printTB_args.Reset(PyRefType::Owned, Py_BuildValue("OOO", py_backtrace.get(), Py_None, stringIO_buffer.get()));
printTB_result.Reset(PyRefType::Owned, PyObject_CallObject(printTB.get(), printTB_args.get()));
stringIO_getvalue.Reset(PyRefType::Owned, PyObject_GetAttrString(stringIO_buffer.get(), "getvalue"));
if (!stringIO_getvalue.IsAllocated())
return retval;
printTB_string.Reset(PyRefType::Owned, PyObject_CallObject(stringIO_getvalue.get(), nullptr));
if (!printTB_string.IsAllocated())
return retval;
PythonString str(PyRefType::Borrowed, printTB_string.get());
llvm::StringRef string_data(str.GetString());
retval.assign(string_data.data(), string_data.size());
return retval;
}
bool
ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
Process* process,