Commit 84c1b974 authored by Tim Peters's avatar Tim Peters

_PyMalloc_{Malloc, Realloc}: Strive to meet the doc's promises about

what these do given a 0 size argument.  This is so that when pymalloc
is enabled, we don't need to wrap pymalloc calls in goofy little
routines special-casing 0.  Note that it's virtually impossible to meet
the doc's promise that malloc(0) will never return NULL; this makes a
best effort, but not an insane effort.  The code does promise that
realloc(not-NULL, 0) will never return NULL (malloc(0) is much harder).

_PyMalloc_Realloc:  Changed to take over all requests for 0 bytes, and
rearranged to be a little quicker in expected cases.

All over the place:  when resorting to the platform allocator, call
free/malloc/realloc directly, without indirecting thru macros.  This
should avoid needing a nightmarish pile of #ifdef-ery if PYMALLOC_DEBUG
is changed so that pymalloc takes over all Py(Mem, Object} memory
operations (which would add useful debugging info to PyMem_xyz
allocations too).
parent 243ea716
...@@ -442,7 +442,7 @@ static block * ...@@ -442,7 +442,7 @@ static block *
new_arena(void) new_arena(void)
{ {
uint excess; /* number of bytes above pool alignment */ uint excess; /* number of bytes above pool alignment */
block *bp = (block *)PyMem_MALLOC(ARENA_SIZE); block *bp = (block *)malloc(ARENA_SIZE);
if (bp == NULL) if (bp == NULL)
return NULL; return NULL;
...@@ -460,7 +460,7 @@ new_arena(void) ...@@ -460,7 +460,7 @@ new_arena(void)
/* Make room for a new entry in the arenas vector. */ /* Make room for a new entry in the arenas vector. */
if (arenas == NULL) { if (arenas == NULL) {
assert(narenas == 0 && maxarenas == 0); assert(narenas == 0 && maxarenas == 0);
arenas = (uptr *)PyMem_MALLOC(16 * sizeof(*arenas)); arenas = (uptr *)malloc(16 * sizeof(*arenas));
if (arenas == NULL) if (arenas == NULL)
goto error; goto error;
maxarenas = 16; maxarenas = 16;
...@@ -509,7 +509,7 @@ new_arena(void) ...@@ -509,7 +509,7 @@ new_arena(void)
uint newmax = maxarenas << 1; uint newmax = maxarenas << 1;
if (newmax <= maxarenas) /* overflow */ if (newmax <= maxarenas) /* overflow */
goto error; goto error;
p = (uptr *)PyMem_MALLOC(newmax * sizeof(*arenas)); p = (uptr *)malloc(newmax * sizeof(*arenas));
if (p == NULL) if (p == NULL)
goto error; goto error;
memcpy(p, arenas, narenas * sizeof(*arenas)); memcpy(p, arenas, narenas * sizeof(*arenas));
...@@ -525,7 +525,7 @@ new_arena(void) ...@@ -525,7 +525,7 @@ new_arena(void)
return bp; return bp;
error: error:
PyMem_FREE(bp); free(bp);
nfreepools = 0; nfreepools = 0;
return NULL; return NULL;
} }
...@@ -552,7 +552,9 @@ error: ...@@ -552,7 +552,9 @@ error:
/*==========================================================================*/ /*==========================================================================*/
/* malloc */ /* malloc. Note that nbytes==0 tries to return a non-NULL pointer, distinct
* from all other currently live pointers. This may not be possible.
*/
/* /*
* The basic blocks are ordered by decreasing execution frequency, * The basic blocks are ordered by decreasing execution frequency,
...@@ -571,7 +573,7 @@ _PyMalloc_Malloc(size_t nbytes) ...@@ -571,7 +573,7 @@ _PyMalloc_Malloc(size_t nbytes)
uint size; uint size;
/* /*
* This implicitly redirects malloc(0) * This implicitly redirects malloc(0).
*/ */
if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) {
LOCK(); LOCK();
...@@ -698,7 +700,7 @@ redirect: ...@@ -698,7 +700,7 @@ redirect:
* last chance to serve the request) or when the max memory limit * last chance to serve the request) or when the max memory limit
* has been reached. * has been reached.
*/ */
return (void *)PyMem_MALLOC(nbytes); return (void *)malloc(nbytes ? nbytes : 1);
} }
/* free */ /* free */
...@@ -782,63 +784,63 @@ _PyMalloc_Free(void *p) ...@@ -782,63 +784,63 @@ _PyMalloc_Free(void *p)
/* We didn't allocate this address. */ /* We didn't allocate this address. */
INCTHEIRS; INCTHEIRS;
PyMem_FREE(p); free(p);
} }
/* realloc */ /* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0,
* then as the Python docs promise, we do not treat this like free(p), and
* return a non-NULL result.
*/
void * void *
_PyMalloc_Realloc(void *p, size_t nbytes) _PyMalloc_Realloc(void *p, size_t nbytes)
{ {
block *bp; void *bp;
poolp pool; poolp pool;
uint size; uint size;
if (p == NULL) if (p == NULL)
return _PyMalloc_Malloc(nbytes); return _PyMalloc_Malloc(nbytes);
/* realloc(p, 0) on big blocks is redirected. */
pool = POOL_ADDR(p); pool = POOL_ADDR(p);
if (ADDRESS_IN_RANGE(p, pool->arenaindex)) { if (ADDRESS_IN_RANGE(p, pool->arenaindex)) {
/* We're in charge of this block */ /* We're in charge of this block */
INCMINE; INCMINE;
size = (pool->szidx + 1) << ALIGNMENT_SHIFT; /* block size */ size = (pool->szidx + 1) << ALIGNMENT_SHIFT; /* block size */
if (size >= nbytes) { if (size >= nbytes)
/* Don't bother if a smaller size was requested /* Don't bother if a smaller size was requested. */
except for realloc(p, 0) == free(p), ret NULL */ return p;
/* XXX but Python guarantees that *its* flavor of /* We need more memory. */
resize(p, 0) will not do a free or return NULL */ assert(nbytes != 0);
if (nbytes == 0) {
_PyMalloc_Free(p);
bp = NULL;
}
else
bp = (block *)p;
}
else {
bp = (block *)_PyMalloc_Malloc(nbytes); bp = (block *)_PyMalloc_Malloc(nbytes);
if (bp != NULL) { if (bp != NULL) {
memcpy(bp, p, size); memcpy(bp, p, size);
_PyMalloc_Free(p); _PyMalloc_Free(p);
} }
return bp;
} }
} /* We're not managing this block. */
else {
/* We haven't allocated this block */
INCTHEIRS; INCTHEIRS;
if (nbytes <= SMALL_REQUEST_THRESHOLD && nbytes) { if (nbytes <= SMALL_REQUEST_THRESHOLD) {
/* small request */ /* Take over this block. */
size = nbytes; bp = _PyMalloc_Malloc(nbytes ? nbytes : 1);
bp = (block *)_PyMalloc_Malloc(nbytes);
if (bp != NULL) { if (bp != NULL) {
memcpy(bp, p, size); memcpy(bp, p, nbytes);
_PyMalloc_Free(p); free(p);
}
else if (nbytes == 0) {
/* Meet the doc's promise that nbytes==0 will
* never return a NULL pointer when p isn't NULL.
*/
bp = p;
} }
} }
else else {
bp = (block *)PyMem_REALLOC(p, nbytes); assert(nbytes != 0);
bp = realloc(p, nbytes);
} }
return (void *)bp; return bp;
} }
#else /* ! WITH_PYMALLOC */ #else /* ! WITH_PYMALLOC */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment