[Python-Dev] PyMem_Realloc corner case

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 MALLOC_ZERO_RETURNS_NULL
> 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 _THIS_REALLOC:
> 
> 			/* Don't bother if a smaller size was requested
> 			   except for realloc(p, 0) == free(p), ret NULL */
> 			if (nbytes == 0) {
> 				_THIS_FREE(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, size_t 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/