[Python-Dev] PyMem_Realloc corner case (original) (raw)

Jason Orendorff jason@jorendorff.com
Thu, 14 Mar 2002 11:54:57 -0600


Tim Peters wrote:

[Jason Orendorff] > I just got bit by the following: > > On Windows,

Which flavor of Windows? Which compiler? Which version of Python?

Ah! I just got this message. You correctly divined the cause of my problems without all this information, so I'll cut to the chase:

[...] realloc'ing to 0 bytes is stupid [...]

Enough said.

I will indulge in a little whining though (below).

MS malloc(0) does not return NULL, which is why MALLOCZERORETURNSNULL should not be #define'd. However, MS realloc(p, 0) returns NULL if and only if p is not NULL (well, MS realloc(NULL, 0) can return NULL if there's not enough heap space remaining to allocate a dummy object), and if p is not NULL does free the block. All of this is fine by the C standard. [...] Note: The pymalloc realloc works just like the MS realloc here, so it's not "just Windows"; from obmalloc.c's THISREALLOC:

/* Don't bother if a smaller size was requested except for realloc(p, 0) == free(p), ret NULL */ if (nbytes == 0) { THISFREE(p); bp = NULL; In fact, I believe it's common for realloc(not-NULL, 0) to act like free(not-NULL), and that's allowed but not required by C.

Well... here's what the standard says:

| 7.20.3 Memory management functions | 1 [...] | If the size of the space requested is zero, the behavior is | implementation-defined: either a null pointer is returned, or the | behavior is as if the size were some nonzero value, except that the | pointer returned shall not be used to access an object.

This applies to calloc, malloc, and realloc. And:

| 7.20.3.4 The realloc function | Synopsis | #include <stdlib.h> | void *realloc(void *ptr, sizet size); | Description | 2 The realloc function deallocates the old object pointed to | by ptr and returns a pointer to a new object that has the size | specified by size. The contents of the new object shall be the | same as that of the old object prior to deallocation, up to the | lesser of the new and old sizes.

If you set knowing how Microsoft's realloc() or PyMalloc's realloc() works, you could read the standard to allow them. But a casual reading suggests

(a) "the behavior is implementation-defined: either X or Y" - a given implementation must pick one or the other, not switch back and forth for different cases. (b) "deallocates the old object...returns a pointer to a new object" - should behave like a free/malloc combo. That is, y=realloc(x, 0); should behave like free(x); y=malloc(0);

Anyway, I'm sure you've had enough of me by now, so I'll stop. :)

Jason Orendorff http://www.jorendorff.com/