Skip to content

Commit 7375212

Browse files
get rid of PythonInteger::GetInteger()
Summary: One small step in my long running quest to improve python exception handling in LLDB. Replace GetInteger() which just returns an int with As<long long> and friends, which return Expected types that can track python exceptions Reviewers: labath, jasonmolenda, JDevlieghere, vadimcn Reviewed By: labath Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D78462
1 parent dad6de4 commit 7375212

File tree

6 files changed

+114
-117
lines changed

6 files changed

+114
-117
lines changed

Diff for: lldb/bindings/python/python-typemaps.swig

+12-24
Original file line numberDiff line numberDiff line change
@@ -59,37 +59,25 @@
5959
$result = list.release();
6060
}
6161

62-
6362
%typemap(in) lldb::tid_t {
64-
if (PythonInteger::Check($input))
65-
{
66-
PythonInteger py_int(PyRefType::Borrowed, $input);
67-
$1 = static_cast<lldb::tid_t>(py_int.GetInteger());
68-
}
69-
else
70-
{
71-
PyErr_SetString(PyExc_ValueError, "Expecting an integer");
63+
PythonObject obj = Retain<PythonObject>($input);
64+
lldb::tid_t value = unwrapOrSetPythonException(As<unsigned long long>(obj));
65+
if (PyErr_Occurred())
7266
return nullptr;
73-
}
67+
$1 = value;
7468
}
7569

7670
%typemap(in) lldb::StateType {
77-
if (PythonInteger::Check($input))
78-
{
79-
PythonInteger py_int(PyRefType::Borrowed, $input);
80-
int64_t state_type_value = py_int.GetInteger() ;
81-
82-
if (state_type_value > lldb::StateType::kLastStateType) {
83-
PyErr_SetString(PyExc_ValueError, "Not a valid StateType value");
84-
return nullptr;
85-
}
86-
$1 = static_cast<lldb::StateType>(state_type_value);
87-
}
88-
else
89-
{
90-
PyErr_SetString(PyExc_ValueError, "Expecting an integer");
71+
PythonObject obj = Retain<PythonObject>($input);
72+
unsigned long long state_type_value =
73+
unwrapOrSetPythonException(As<unsigned long long>(obj));
74+
if (PyErr_Occurred())
75+
return nullptr;
76+
if (state_type_value > lldb::StateType::kLastStateType) {
77+
PyErr_SetString(PyExc_ValueError, "Not a valid StateType value");
9178
return nullptr;
9279
}
80+
$1 = static_cast<lldb::StateType>(state_type_value);
9381
}
9482

9583
/* Typemap definitions to allow SWIG to properly handle char buffer. */

Diff for: lldb/bindings/python/python-wrapper.swig

+17-24
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ LLDBSwigPythonCallBreakpointResolver
444444
if (PyErr_Occurred())
445445
{
446446
PyErr_Print();
447+
PyErr_Clear();
447448
return 0;
448449
}
449450

@@ -457,11 +458,13 @@ LLDBSwigPythonCallBreakpointResolver
457458
return 1;
458459
}
459460

460-
PythonInteger int_result = result.AsType<PythonInteger>();
461-
if (!int_result.IsAllocated())
462-
return 0;
461+
long long ret_val = unwrapOrSetPythonException(As<long long>(result));
463462

464-
unsigned int ret_val = int_result.GetInteger();
463+
if (PyErr_Occurred()) {
464+
PyErr_Print();
465+
PyErr_Clear();
466+
return 0;
467+
}
465468

466469
return ret_val;
467470
}
@@ -515,26 +518,17 @@ LLDBSwigPython_CalculateNumChildren
515518
return 0;
516519
}
517520

518-
PythonObject result;
519-
521+
size_t ret_val;
520522
if (arg_info.get().max_positional_args < 1)
521-
result = pfunc();
523+
ret_val = unwrapOrSetPythonException(As<long long>(pfunc.Call()));
522524
else
523-
result = pfunc(PythonInteger(max));
524-
525-
if (!result.IsAllocated())
526-
return 0;
527-
528-
PythonInteger int_result = result.AsType<PythonInteger>();
529-
if (!int_result.IsAllocated())
530-
return 0;
531-
532-
size_t ret_val = int_result.GetInteger();
525+
ret_val = unwrapOrSetPythonException(As<long long>(pfunc.Call(PythonInteger(max))));
533526

534-
if (PyErr_Occurred()) //FIXME use Expected to catch python exceptions
527+
if (PyErr_Occurred())
535528
{
536529
PyErr_Print();
537530
PyErr_Clear();
531+
return 0;
538532
}
539533

540534
if (arg_info.get().max_positional_args < 1)
@@ -588,16 +582,15 @@ LLDBSwigPython_GetIndexOfChildWithName
588582
if (!pfunc.IsAllocated())
589583
return UINT32_MAX;
590584

591-
PythonObject result = pfunc(PythonString(child_name));
585+
llvm::Expected<PythonObject> result = pfunc.Call(PythonString(child_name));
592586

593-
if (!result.IsAllocated())
594-
return UINT32_MAX;
587+
long long retval = unwrapOrSetPythonException(As<long long>(std::move(result)));
595588

596-
PythonInteger int_result = result.AsType<PythonInteger>();
597-
if (!int_result.IsAllocated())
589+
if (PyErr_Occurred()) {
590+
PyErr_Clear(); // FIXME print this? do something else
598591
return UINT32_MAX;
592+
}
599593

600-
int64_t retval = int_result.GetInteger();
601594
if (retval >= 0)
602595
return (uint32_t)retval;
603596

Diff for: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp

+19-21
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@ template <>
4444
Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) {
4545
if (!obj)
4646
return obj.takeError();
47-
return obj.get().AsLongLong();
47+
return obj->AsLongLong();
48+
}
49+
50+
template <>
51+
Expected<unsigned long long>
52+
python::As<unsigned long long>(Expected<PythonObject> &&obj) {
53+
if (!obj)
54+
return obj.takeError();
55+
return obj->AsUnsignedLongLong();
4856
}
4957

5058
template <>
@@ -463,32 +471,22 @@ void PythonInteger::Convert(PyRefType &type, PyObject *&py_obj) {
463471
#endif
464472
}
465473

466-
int64_t PythonInteger::GetInteger() const {
467-
if (m_py_obj) {
468-
assert(PyLong_Check(m_py_obj) &&
469-
"PythonInteger::GetInteger has a PyObject that isn't a PyLong");
470-
471-
int overflow = 0;
472-
int64_t result = PyLong_AsLongLongAndOverflow(m_py_obj, &overflow);
473-
if (overflow != 0) {
474-
// We got an integer that overflows, like 18446744072853913392L we can't
475-
// use PyLong_AsLongLong() as it will return 0xffffffffffffffff. If we
476-
// use the unsigned long long it will work as expected.
477-
const uint64_t uval = PyLong_AsUnsignedLongLong(m_py_obj);
478-
result = static_cast<int64_t>(uval);
479-
}
480-
return result;
481-
}
482-
return UINT64_MAX;
483-
}
484-
485474
void PythonInteger::SetInteger(int64_t value) {
486475
*this = Take<PythonInteger>(PyLong_FromLongLong(value));
487476
}
488477

489478
StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {
490479
StructuredData::IntegerSP result(new StructuredData::Integer);
491-
result->SetValue(GetInteger());
480+
// FIXME this is really not ideal. Errors are silently converted to 0
481+
// and overflows are silently wrapped. But we'd need larger changes
482+
// to StructuredData to fix it, so that's how it is for now.
483+
llvm::Expected<unsigned long long> value = AsModuloUnsignedLongLong();
484+
if (!value) {
485+
llvm::consumeError(value.takeError());
486+
result->SetValue(0);
487+
} else {
488+
result->SetValue(value.get());
489+
}
492490
return result;
493491
}
494492

Diff for: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h

+25-2
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,27 @@ class PythonObject {
370370
return r;
371371
}
372372

373+
llvm::Expected<long long> AsUnsignedLongLong() {
374+
if (!m_py_obj)
375+
return nullDeref();
376+
assert(!PyErr_Occurred());
377+
long long r = PyLong_AsUnsignedLongLong(m_py_obj);
378+
if (PyErr_Occurred())
379+
return exception();
380+
return r;
381+
}
382+
383+
llvm::Expected<unsigned long long> AsModuloUnsignedLongLong() const {
384+
// wraps on overflow, instead of raising an error.
385+
if (!m_py_obj)
386+
return nullDeref();
387+
assert(!PyErr_Occurred());
388+
unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj);
389+
if (PyErr_Occurred())
390+
return exception();
391+
return r;
392+
}
393+
373394
llvm::Expected<bool> IsInstance(const PythonObject &cls) {
374395
if (!m_py_obj || !cls.IsValid())
375396
return nullDeref();
@@ -399,6 +420,10 @@ template <> llvm::Expected<bool> As<bool>(llvm::Expected<PythonObject> &&obj);
399420
template <>
400421
llvm::Expected<long long> As<long long>(llvm::Expected<PythonObject> &&obj);
401422

423+
template <>
424+
llvm::Expected<unsigned long long>
425+
As<unsigned long long>(llvm::Expected<PythonObject> &&obj);
426+
402427
template <>
403428
llvm::Expected<std::string> As<std::string>(llvm::Expected<PythonObject> &&obj);
404429

@@ -491,8 +516,6 @@ class PythonInteger : public TypedPythonObject<PythonInteger> {
491516
static bool Check(PyObject *py_obj);
492517
static void Convert(PyRefType &type, PyObject *&py_obj);
493518

494-
int64_t GetInteger() const;
495-
496519
void SetInteger(int64_t value);
497520

498521
StructuredData::IntegerSP CreateStructuredInteger() const;

Diff for: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

+4-9
Original file line numberDiff line numberDiff line change
@@ -3150,20 +3150,15 @@ uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject(
31503150
if (PyErr_Occurred())
31513151
PyErr_Clear();
31523152

3153-
// right now we know this function exists and is callable..
3154-
PythonObject py_return(
3155-
PyRefType::Owned,
3156-
PyObject_CallMethod(implementor.get(), callee_name, nullptr));
3153+
long long py_return = unwrapOrSetPythonException(
3154+
As<long long>(implementor.CallMethod(callee_name)));
31573155

31583156
// if it fails, print the error but otherwise go on
31593157
if (PyErr_Occurred()) {
31603158
PyErr_Print();
31613159
PyErr_Clear();
3162-
}
3163-
3164-
if (py_return.IsAllocated() && PythonInteger::Check(py_return.get())) {
3165-
PythonInteger int_value(PyRefType::Borrowed, py_return.get());
3166-
result = int_value.GetInteger();
3160+
} else {
3161+
result = py_return;
31673162
}
31683163

31693164
return result;

0 commit comments

Comments
 (0)