[Python-Dev] Use of PyObject_NEW
Tim Peters
tim.one@comcast.net
Fri, 15 Mar 2002 03:29:06 -0500
[Martin v. Loewis]
> I tried to understand the various memory allocation function and
> macros in Python, and found that there is probably a misunderstanding
> in what PyObject_NEW does.
>
> For example, PyRange_New says
>
> rangeobject *obj = PyObject_NEW(rangeobject, &PyRange_Type);
>
> if (obj == NULL)
> return NULL;
>
> The assumption apparently is that somebody will raise a MemoryError
> and return NULL when allocation fails. However, this code expands to
>
> rangeobject *obj = ((rangeobject*)PyObject_Init(
> (PyObject *) malloc(((&PyRange_Type)->tp_basicsize)),
> (&PyRange_Type)));
>
> if (obj == ((void *)0) )
> return ((void *)0) ;
>
> malloc will just return NULL in case of failure, and PyObject_Init
> starts with
>
> if (op == NULL) {
> PyErr_SetString(PyExc_SystemError,
> "NULL object passed to PyObject_Init");
> return op;
> }
>
> So instead of a MemoryError, you will get a SystemError if the system
> runs out of memory. Is that intentional?
Not credible -- it's a bug. PyObject_NEW and PyObject_New should behave
alike, and PyObject_New does set MemoryError in this case (via
_PyObject_New().
> The documentation says
>
> Macro version of \cfunction{PyObject_New()}, to gain performance at
> the expense of safety. This does not check \var{type} for a \NULL{}
> value.
>
> This is incorrect: It does check for NULL.
No, it's correct: as stated, it does not check \var{type} for a NULL. Note
that the docs name the *second* argument "type", while the macro names the
first argument "type". Neither PyObject_New nor PyObject_NEW check their
second argument for NULL (so it's a minor mystery too why the docs bother to
point this out only for PyObject_NEW).
> It also does not help to gain performance - PyObject_New has three
> calls (_PyObject_New, malloc, _Py_NewReference), and so does
> PyObject_NEW (malloc, PyObject_Init, _Py_NewReference).
>
> I recommend to deprecate PyObject_NEW (and correspondingly
> PyObject_NEW_VAR, PyObject_DEL).
I think that's pointless -- lots of code uses these things, and we have no
effective way to deprecate pieces of the C API anyway. I'd be in favor of
redefining
#define PyObject_NEW PyObject_New
to get rid of the MemoryError bug, though.