Skip to content

Commit a47b70f

Browse files
committed
Convert PyDict_GetXXX to internal error checking variant
1 parent f067deb commit a47b70f

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

include/pybind11/pybind11.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ class cpp_function : public function {
636636
bool bad_arg = false;
637637
for (; args_copied < args_to_copy; ++args_copied) {
638638
const argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;
639-
if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) {
639+
if (kwargs_in && arg_rec && arg_rec->name && dict_getitemstring(kwargs_in, arg_rec->name)) {
640640
bad_arg = true;
641641
break;
642642
}
@@ -684,7 +684,7 @@ class cpp_function : public function {
684684

685685
handle value;
686686
if (kwargs_in && arg_rec.name)
687-
value = PyDict_GetItemString(kwargs.ptr(), arg_rec.name);
687+
value = dict_getitemstring(kwargs.ptr(), arg_rec.name);
688688

689689
if (value) {
690690
// Consume a kwargs value
@@ -2139,7 +2139,7 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty
21392139
if (frame && (std::string) str(frame->f_code->co_name) == name &&
21402140
frame->f_code->co_argcount > 0) {
21412141
PyFrame_FastToLocals(frame);
2142-
PyObject *self_caller = PyDict_GetItem(
2142+
PyObject *self_caller = dict_getitem(
21432143
frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));
21442144
if (self_caller == self.ptr())
21452145
return function();

include/pybind11/pytypes.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,43 @@ inline handle get_function(handle value) {
485485
return value;
486486
}
487487

488+
// Reimplementation of python's dict helper functions to ensure that exceptions
489+
// aren't swallowed (see #2862)
490+
491+
// copied from cpython _PyDict_GetItemStringWithError
492+
inline PyObject * dict_getitemstring(PyObject *v, const char *key)
493+
{
494+
#if PY_MAJOR_VERSION >= 3
495+
PyObject *kv, *rv;
496+
kv = PyUnicode_FromString(key);
497+
if (kv == NULL) {
498+
throw error_already_set();
499+
}
500+
501+
rv = PyDict_GetItemWithError(v, kv);
502+
Py_DECREF(kv);
503+
if (rv == NULL && PyErr_Occurred()) {
504+
throw error_already_set();
505+
}
506+
return rv;
507+
#else
508+
return PyDict_GetItemString(v, key);
509+
#endif
510+
}
511+
512+
inline PyObject * dict_getitem(PyObject *v, PyObject *key)
513+
{
514+
#if PY_MAJOR_VERSION >= 3
515+
PyObject *rv = PyDict_GetItemWithError(v, key);
516+
if (rv == NULL && PyErr_Occurred()) {
517+
throw error_already_set();
518+
}
519+
return rv;
520+
#else
521+
return PyDict_GetItem(v, key);
522+
#endif
523+
}
524+
488525
// Helper aliases/functions to support implicit casting of values given to python accessors/methods.
489526
// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes
490527
// through pybind11::cast(obj) to convert it to an `object`.

0 commit comments

Comments
 (0)