[Python-Dev] Activating pymalloc

Tim Peters tim.one@comcast.net
Fri, 15 Mar 2002 04:52:59 -0500


[Tim]
>> Are "the right" alloc/dealloc macros documented anywhere?  I can't
>> find it, if they are.

[Martin]
> http://www.python.org/doc/current/api/memoryInterface.html
>
> is as precise and comprehensive as anything I would have written
> myself.

Then no wonder extension authors can't get this right <0.9 wink>.

> The Examples even give explicit examples what cases to avoid.

Heh -- I never noticed the examples before.  It's curious that they claim

    PyMem_Del(buf3);  /* Wrong -- should be PyMem_Free() */

when the docs just finished saying

    void PyMem_Del(void *p)
        Same as PyMem_Free().

Either the example or the doc's "same as" is incomprehensible.

It's also curious that the examples say

    free(buf1);       /* Fatal -- should be PyMem_Del()  */

when the docs said no such thing (and this may be the #1 error in practice).
The Examples page (but not the docs) says

    Indeed, it is required to use the same memory API family for a given
    memory block,

but the crucial phrase "the same memory API family" is left undefined.  At a
minimum, it needs to identify "the memory API families" by explicit,
exhaustive enumeration.  The mess in practice is a fact, and proves people
don't understand what the docs are *trying* to say here.  I'm not sure
myself.

Like, are the functions and macros interchangeable?  For example, if you
know something was allocated via PyMem_Malloc, is it OK to release it via
PyMem_FREE?  I simply can't guess from what the docs say, again because what
constitutes "a family" is left undefined.

> For PyObject, the equivalent documentation is at
>
> http://www.python.org/doc/current/api/allocating-objects.html

I'll be charitable and guess this defines a different family <wink>.

Note that users also have to know about

http://www.python.org/doc/current/api/supporting-cycle-detection.html

in order to get at

    PyObject_GC_New / PyObject_GC_NewVar / PyObject_GC_Del

So far we've covered more than two dozen spellings (even without plain
"malloc" and "free"), spread over at least 4 manual pages.  One compact
table listing all of them in "legal" pairs would be an enormous help.

> ...
> Do you think you would understand the documentation that is currently
> there?

Not well enough to use with confidence, no.  I've seen the docs before,
although I did miss the Examples section previously.  I have a fancy editor
with an integrated symbol database, and in practice I chase down the macros
and functions until I see what they *do* at the leaves.  The endless layers
of indirection macros make this quite a pain (and I see you resorted to
looking at post-preprocessor listings).

> BTW, I found the documentation by grepping for PyMem_ in all .tex
> files, because I could not be bothered to read the online version,
> either.

They're easy to find via the index in the C API manual.

> It leaves out a good many details (i.e. additional API), but I think
> this is deliberate - you are not supposed to ever use this other API,
> anyway.

Which API?

> I wonder whether one could design a script that analyses Python code
> for asymmetric usage of memory management functions, e.g. trying to
> match
>
>    expression->FIELD = ALLOCATOR;
>    DEALLOCATOR(other_expression->FIELD);
>
> This would complain if there is a FIELD that has no symmetric usage,
> or if a certain allocator has no counterpart at all in a source file.
>
> I then wonder if that script would have found the errors you cite.

Well, to a first approximation, just searching for "free(" is valuable!  In
the Python source, the thread implementations use malloc and free on
purpose, but it also turns up a curious

		    free((char *)Py_FileSystemDefaultEncoding);

in _localmodule.c.  If not an outright bug, that's at least begging for a
comment, as the only obvious definition is in bltinmodule.c:

#if defined(MS_WIN32) && defined(HAVE_USABLE_WCHAR_T)
const char *Py_FileSystemDefaultEncoding = "mbcs";
#else
const char *Py_FileSystemDefaultEncoding = NULL; /* use default */
#endif

Does that mean that, on Windows, we may free() a static char*?!