Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-32787: Better error handling in ctypes. #3727

Merged
merged 11 commits into from
Dec 5, 2018
158 changes: 107 additions & 51 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ PyObject *
PyDict_GetItemProxy(PyObject *dict, PyObject *key)
{
PyObject *result;
PyObject *item = PyDict_GetItem(dict, key);
PyObject *item = PyDict_GetItemWithError(dict, key);

if (item == NULL)
return NULL;
Expand Down Expand Up @@ -426,6 +426,8 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
PyTypeObject *result;
PyObject *fields;
StgDictObject *dict;
_Py_IDENTIFIER(_abstract_);
_Py_IDENTIFIER(_fields_);

/* create the new instance (which is a class,
since we are a metatype!) */
Expand All @@ -434,8 +436,12 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
return NULL;

/* keep this for bw compatibility */
if (PyDict_GetItemString(result->tp_dict, "_abstract_"))
if (_PyDict_GetItemIdWithError(result->tp_dict, &PyId__abstract_))
return (PyObject *)result;
if (PyErr_Occurred()) {
Py_DECREF(result);
return NULL;
}

dict = (StgDictObject *)_PyObject_CallNoArg((PyObject *)&PyCStgDict_Type);
if (!dict) {
Expand All @@ -458,8 +464,21 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt

dict->paramfunc = StructUnionType_paramfunc;

fields = PyDict_GetItemString((PyObject *)dict, "_fields_");
if (!fields) {
fields = _PyDict_GetItemIdWithError((PyObject *)dict, &PyId__fields_);
if (fields) {
if (-1 == PyObject_SetAttr((PyObject *)result,
_PyUnicode_FromId(&PyId__fields_), fields))
{
Py_DECREF(result);
return NULL;
}
return (PyObject *)result;
}
else if (PyErr_Occurred()) {
Py_DECREF(result);
return NULL;
}
else {
StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base);

if (basedict == NULL)
Expand All @@ -473,12 +492,6 @@ StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isSt
basedict->flags |= DICTFLAG_FINAL; /* set the 'final' flag in the baseclass dict */
return (PyObject *)result;
}

if (-1 == PyObject_SetAttrString((PyObject *)result, "_fields_", fields)) {
Py_DECREF(result);
return NULL;
}
return (PyObject *)result;
}

static PyObject *
Expand Down Expand Up @@ -961,6 +974,7 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
StgDictObject *stgdict;
PyObject *proto;
PyObject *typedict;
_Py_IDENTIFIER(_type_);

typedict = PyTuple_GetItem(args, 2);
if (!typedict)
Expand All @@ -980,15 +994,15 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
stgdict->paramfunc = PyCPointerType_paramfunc;
stgdict->flags |= TYPEFLAG_ISPOINTER;

proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */
if (proto && -1 == PyCPointerType_SetProto(stgdict, proto)) {
Py_DECREF((PyObject *)stgdict);
return NULL;
}

proto = _PyDict_GetItemIdWithError(typedict, &PyId__type_); /* Borrowed ref */
if (proto) {
StgDictObject *itemdict = PyType_stgdict(proto);
StgDictObject *itemdict;
const char *current_format;
if (-1 == PyCPointerType_SetProto(stgdict, proto)) {
Py_DECREF((PyObject *)stgdict);
return NULL;
}
itemdict = PyType_stgdict(proto);
/* PyCPointerType_SetProto has verified proto has a stgdict. */
assert(itemdict);
/* If itemdict->format is NULL, then this is a pointer to an
Expand All @@ -1009,6 +1023,10 @@ PyCPointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
}
else if (PyErr_Occurred()) {
Py_DECREF((PyObject *)stgdict);
return NULL;
}

/* create the new instance (which is a class,
since we are a metatype!) */
Expand All @@ -1034,6 +1052,7 @@ static PyObject *
PyCPointerType_set_type(PyTypeObject *self, PyObject *type)
{
StgDictObject *dict;
_Py_IDENTIFIER(_type_);

dict = PyType_stgdict((PyObject *)self);
if (!dict) {
Expand All @@ -1045,7 +1064,7 @@ PyCPointerType_set_type(PyTypeObject *self, PyObject *type)
if (-1 == PyCPointerType_SetProto(dict, type))
return NULL;

if (-1 == PyDict_SetItemString((PyObject *)dict, "_type_", type))
if (-1 == _PyDict_SetItemId((PyObject *)dict, &PyId__type_, type))
return NULL;

Py_RETURN_NONE;
Expand Down Expand Up @@ -2278,6 +2297,10 @@ make_funcptrtype_dict(StgDictObject *stgdict)
{
PyObject *ob;
PyObject *converters = NULL;
_Py_IDENTIFIER(_flags_);
_Py_IDENTIFIER(_argtypes_);
_Py_IDENTIFIER(_restype_);
_Py_IDENTIFIER(_check_retval_);

stgdict->align = _ctypes_get_fielddesc("P")->pffi_type->alignment;
stgdict->length = 1;
Expand All @@ -2286,26 +2309,31 @@ make_funcptrtype_dict(StgDictObject *stgdict)
stgdict->getfunc = NULL;
stgdict->ffi_type_pointer = ffi_type_pointer;

ob = PyDict_GetItemString((PyObject *)stgdict, "_flags_");
ob = _PyDict_GetItemIdWithError((PyObject *)stgdict, &PyId__flags_);
if (!ob || !PyLong_Check(ob)) {
PyErr_SetString(PyExc_TypeError,
"class must define _flags_ which must be an integer");
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_TypeError,
"class must define _flags_ which must be an integer");
}
return -1;
}
stgdict->flags = PyLong_AS_LONG(ob) | TYPEFLAG_ISPOINTER;
stgdict->flags = PyLong_AsUnsignedLongMask(ob) | TYPEFLAG_ISPOINTER;

/* _argtypes_ is optional... */
ob = PyDict_GetItemString((PyObject *)stgdict, "_argtypes_");
ob = _PyDict_GetItemIdWithError((PyObject *)stgdict, &PyId__argtypes_);
if (ob) {
converters = converters_from_argtypes(ob);
if (!converters)
goto error;
return -1;
Py_INCREF(ob);
stgdict->argtypes = ob;
stgdict->converters = converters;
}
else if (PyErr_Occurred()) {
return -1;
}

ob = PyDict_GetItemString((PyObject *)stgdict, "_restype_");
ob = _PyDict_GetItemIdWithError((PyObject *)stgdict, &PyId__restype_);
if (ob) {
if (ob != Py_None && !PyType_stgdict(ob) && !PyCallable_Check(ob)) {
PyErr_SetString(PyExc_TypeError,
Expand All @@ -2314,12 +2342,17 @@ make_funcptrtype_dict(StgDictObject *stgdict)
}
Py_INCREF(ob);
stgdict->restype = ob;
stgdict->checker = PyObject_GetAttrString(ob, "_check_retval_");
if (stgdict->checker == NULL)
PyErr_Clear();
if (_PyObject_LookupAttrId(ob, &PyId__check_retval_,
&stgdict->checker) < 0)
{
return -1;
}
}
else if (PyErr_Occurred()) {
return -1;
}
/* XXX later, maybe.
ob = PyDict_GetItemString((PyObject *)stgdict, "_errcheck_");
ob = _PyDict_GetItemIdWithError((PyObject *)stgdict, &PyId__errcheck_);
if (ob) {
if (!PyCallable_Check(ob)) {
PyErr_SetString(PyExc_TypeError,
Expand All @@ -2329,13 +2362,11 @@ make_funcptrtype_dict(StgDictObject *stgdict)
Py_INCREF(ob);
stgdict->errcheck = ob;
}
else if (PyErr_Occurred()) {
return -1;
}
*/
return 0;

error:
Py_XDECREF(converters);
return -1;

}

static PyCArgObject *
Expand Down Expand Up @@ -3511,9 +3542,12 @@ PyCFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
like that.
*/
/*
if (kwds && PyDict_GetItemString(kwds, "options")) {
if (kwds && _PyDict_GetItemIdWithError(kwds, &PyId_options)) {
...
}
else if (PyErr_Occurred()) {
return NULL;
}
*/

dict = PyType_stgdict((PyObject *)type);
Expand Down Expand Up @@ -3590,10 +3624,16 @@ _get_arg(int *pindex, PyObject *name, PyObject *defval, PyObject *inargs, PyObje
Py_INCREF(v);
return v;
}
if (kwds && name && (v = PyDict_GetItem(kwds, name))) {
++*pindex;
Py_INCREF(v);
return v;
if (kwds && name) {
v = PyDict_GetItemWithError(kwds, name);
if (v) {
++*pindex;
Py_INCREF(v);
return v;
}
else if (PyErr_Occurred()) {
return NULL;
}
}
if (defval) {
Py_INCREF(defval);
Expand Down Expand Up @@ -3670,15 +3710,15 @@ _build_callargs(PyCFuncPtrObject *self, PyObject *argtypes,
for (i = 0; i < len; ++i) {
PyObject *item = PyTuple_GET_ITEM(paramflags, i);
PyObject *ob;
int flag;
unsigned int flag;
PyObject *name = NULL;
PyObject *defval = NULL;

/* This way seems to be ~2 us faster than the PyArg_ParseTuple
calls below. */
/* We HAVE already checked that the tuple can be parsed with "i|ZO", so... */
Py_ssize_t tsize = PyTuple_GET_SIZE(item);
flag = PyLong_AS_LONG(PyTuple_GET_ITEM(item, 0));
flag = PyLong_AsUnsignedLongMask(PyTuple_GET_ITEM(item, 0));
name = tsize > 1 ? PyTuple_GET_ITEM(item, 1) : NULL;
defval = tsize > 2 ? PyTuple_GET_ITEM(item, 2) : NULL;

Expand Down Expand Up @@ -3758,7 +3798,7 @@ _build_callargs(PyCFuncPtrObject *self, PyObject *argtypes,
break;
default:
PyErr_Format(PyExc_ValueError,
"paramflag %d not yet implemented", flag);
"paramflag %u not yet implemented", flag);
goto error;
break;
}
Expand Down Expand Up @@ -4121,6 +4161,7 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
StgDictObject *dict;
PyObject *fields;
Py_ssize_t i;
_Py_IDENTIFIER(_fields_);

if (PyType_stgdict((PyObject *)type->tp_base)) {
index = _init_pos_args(self, type->tp_base,
Expand All @@ -4131,9 +4172,13 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
}

dict = PyType_stgdict((PyObject *)type);
fields = PyDict_GetItemString((PyObject *)dict, "_fields_");
if (fields == NULL)
fields = _PyDict_GetItemIdWithError((PyObject *)dict, &PyId__fields_);
if (fields == NULL) {
if (PyErr_Occurred()) {
return -1;
}
return index;
}

for (i = 0;
i < dict->length && (i+index) < PyTuple_GET_SIZE(args);
Expand All @@ -4149,13 +4194,20 @@ _init_pos_args(PyObject *self, PyTypeObject *type,
return -1;
}
val = PyTuple_GET_ITEM(args, i + index);
if (kwds && PyDict_GetItem(kwds, name)) {
PyErr_Format(PyExc_TypeError,
"duplicate values for field %R",
name);
Py_DECREF(pair);
Py_DECREF(name);
return -1;
if (kwds) {
if (PyDict_GetItemWithError(kwds, name)) {
PyErr_Format(PyExc_TypeError,
"duplicate values for field %R",
name);
Py_DECREF(pair);
Py_DECREF(name);
return -1;
}
else if (PyErr_Occurred()) {
Py_DECREF(pair);
Py_DECREF(name);
return -1;
}
}

res = PyObject_SetAttr(self, name, val);
Expand Down Expand Up @@ -4626,6 +4678,10 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length)
Py_DECREF(key);
return result;
}
else if (PyErr_Occurred()) {
Py_DECREF(key);
return NULL;
}

if (!PyType_Check(itemtype)) {
PyErr_SetString(PyExc_TypeError,
Expand Down
7 changes: 6 additions & 1 deletion Modules/_ctypes/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,14 @@ static void
TryAddRef(StgDictObject *dict, CDataObject *obj)
{
IUnknown *punk;
_Py_IDENTIFIER(_needs_com_addref_);

if (NULL == PyDict_GetItemString((PyObject *)dict, "_needs_com_addref_"))
if (!_PyDict_GetItemIdWithError((PyObject *)dict, &PyId__needs_com_addref_)) {
if (PyErr_Occurred()) {
PrintError("getting _needs_com_addref_");
}
return;
}

punk = *(IUnknown **)obj->b_ptr;
if (punk)
Expand Down
Loading