type_call() now detect bugs in type new and init

* Call _Py_CheckFunctionResult() to check for bugs in type
  constructors (tp_new)
* Add assertions to ensure an exception was raised if tp_init failed
  or that no exception was raised if tp_init succeed

Refactor also the function to have less indentation.
This commit is contained in:
Victor Stinner 2015-09-03 12:16:49 +02:00
parent 31eb5fbe89
commit 99bb14bf0c
1 changed files with 27 additions and 19 deletions

View File

@ -906,25 +906,33 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
#endif #endif
obj = type->tp_new(type, args, kwds); obj = type->tp_new(type, args, kwds);
if (obj != NULL) { obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
/* Ugly exception: when the call was type(something), if (obj == NULL)
don't call tp_init on the result. */ return NULL;
if (type == &PyType_Type &&
PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && /* Ugly exception: when the call was type(something),
(kwds == NULL || don't call tp_init on the result. */
(PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) if (type == &PyType_Type &&
return obj; PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
/* If the returned object is not an instance of type, (kwds == NULL ||
it won't be initialized. */ (PyDict_Check(kwds) && PyDict_Size(kwds) == 0)))
if (!PyType_IsSubtype(Py_TYPE(obj), type)) return obj;
return obj;
type = Py_TYPE(obj); /* If the returned object is not an instance of type,
if (type->tp_init != NULL) { it won't be initialized. */
int res = type->tp_init(obj, args, kwds); if (!PyType_IsSubtype(Py_TYPE(obj), type))
if (res < 0) { return obj;
Py_DECREF(obj);
obj = NULL; type = Py_TYPE(obj);
} if (type->tp_init != NULL) {
int res = type->tp_init(obj, args, kwds);
if (res < 0) {
assert(PyErr_Occurred());
Py_DECREF(obj);
obj = NULL;
}
else {
assert(!PyErr_Occurred());
} }
} }
return obj; return obj;