Skip to content

Commit a5d78cc

Browse files
committed
Whether platform malloc(0) returns NULL has nothing to do with whether
platform realloc(p, 0) returns NULL, so MALLOC_ZERO_RETURNS_NULL can be correctly undefined yet realloc(p, 0) can return NULL anyway. Prevent realloc(p, 0) doing free(p) and returning NULL via a different hack. Would probably be better to get rid of MALLOC_ZERO_RETURNS_NULL entirely. Bugfix candidate.
1 parent b77d343 commit a5d78cc

File tree

3 files changed

+24
-14
lines changed

3 files changed

+24
-14
lines changed

Include/pymem.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,18 @@ extern DL_IMPORT(void) PyMem_Free(void *);
111111
/* Macros */
112112
#define PyMem_NEW(type, n) \
113113
( (type *) PyMem_MALLOC(_PyMem_EXTRA + (n) * sizeof(type)) )
114-
#define PyMem_RESIZE(p, type, n) \
115-
if ((p) == NULL) \
116-
(p) = (type *)(PyMem_MALLOC( \
117-
_PyMem_EXTRA + (n) * sizeof(type))); \
118-
else \
119-
(p) = (type *)(PyMem_REALLOC((p), \
120-
_PyMem_EXTRA + (n) * sizeof(type)))
114+
115+
/* See comment near MALLOC_ZERO_RETURNS_NULL in pyport.h. */
116+
#define PyMem_RESIZE(p, type, n) \
117+
do { \
118+
size_t _sum = (n) * sizeof(type); \
119+
if (!_sum) \
120+
_sum = 1; \
121+
(p) = (type *)((p) ? \
122+
PyMem_REALLOC(p, _sum) : \
123+
PyMem_MALLOC(_sum)); \
124+
} while (0)
125+
121126
#define PyMem_DEL(p) PyMem_FREE(p)
122127

123128
/* PyMem_XDEL is deprecated. To avoid the call when p is NULL,

Include/pyport.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,16 @@ extern double hypot(double, double);
366366
#endif
367367

368368
#ifdef MALLOC_ZERO_RETURNS_NULL
369-
/* XXX Always allocate one extra byte, since some malloc's return NULL
370-
XXX for malloc(0) or realloc(p, 0). */
369+
/* Allocate an extra byte if the platform malloc(0) returns NULL.
370+
Caution: this bears no relation to whether realloc(p, 0) returns NULL
371+
when p != NULL. Even on platforms where malloc(0) does not return NULL,
372+
realloc(p, 0) may act like free(p) and return NULL. Examples include
373+
Windows, and Python's own obmalloc.c (as of 2-Mar-2002). For whatever
374+
reason, our docs promise that PyMem_Realloc(p, 0) won't act like
375+
free(p) or return NULL, so realloc() calls may have to be hacked
376+
too, but MALLOC_ZERO_RETURNS_NULL's state is irrelevant to realloc (it
377+
needs a different hack).
378+
*/
371379
#define _PyMem_EXTRA 1
372380
#else
373381
#define _PyMem_EXTRA 0

Objects/object.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,11 +1894,8 @@ PyMem_Malloc(size_t nbytes)
18941894
void *
18951895
PyMem_Realloc(void *p, size_t nbytes)
18961896
{
1897-
#if _PyMem_EXTRA > 0
1898-
if (nbytes == 0)
1899-
nbytes = _PyMem_EXTRA;
1900-
#endif
1901-
return PyMem_REALLOC(p, nbytes);
1897+
/* See comment near MALLOC_ZERO_RETURNS_NULL in pyport.h. */
1898+
return PyMem_REALLOC(p, nbytes ? nbytes : 1);
19021899
}
19031900

19041901
void

0 commit comments

Comments
 (0)