SF bug 542181: Realloc behavior

The bug report pointed out a bogosity in the comment block explaining
thread safety for arena management.  Repaired that comment, repaired a
couple others while I was at it, and added an assert.

_PyMalloc_DebugRealloc:  If this needed to get more memory, but couldn't,
it erroneously freed the original memory.  Repaired that.

This is for 2.3 only (unless we decide to backport the new pymalloc).
This commit is contained in:
Tim Peters 2002-04-11 06:36:45 +00:00
parent 362ed3451e
commit 52aefc8a7b
1 changed files with 16 additions and 12 deletions

View File

@ -321,13 +321,14 @@ pymalloc strives at all levels (arena, pool, and block) never to touch a piece
of memory until it's actually needed. of memory until it's actually needed.
So long as a pool is in the used state, we're certain there *is* a block So long as a pool is in the used state, we're certain there *is* a block
available for allocating. If pool->freeblock is NULL then, that means we available for allocating, and pool->freeblock is not NULL. If pool->freeblock
simply haven't yet gotten to one of the higher-address blocks. The offset points to the end of the free list before we've carved the entire pool into
from the pool_header to the start of "the next" virgin block is stored in blocks, that means we simply haven't yet gotten to one of the higher-address
the pool_header nextoffset member, and the largest value of nextoffset that blocks. The offset from the pool_header to the start of "the next" virgin
makes sense is stored in the maxnextoffset member when a pool is initialized. block is stored in the pool_header nextoffset member, and the largest value
All the blocks in a pool have been passed out at least once when and only of nextoffset that makes sense is stored in the maxnextoffset member when a
when nextoffset > maxnextoffset. pool is initialized. All the blocks in a pool have been passed out at least
once when and only when nextoffset > maxnextoffset.
Major obscurity: While the usedpools vector is declared to have poolp Major obscurity: While the usedpools vector is declared to have poolp
@ -467,8 +468,7 @@ new_arena(void)
maxarenas = 16; maxarenas = 16;
} }
else if (narenas == maxarenas) { else if (narenas == maxarenas) {
/* Grow arenas. Don't use realloc: if this fails, we /* Grow arenas.
* don't want to lose the base addresses we already have.
* *
* Exceedingly subtle: Someone may be calling the pymalloc * Exceedingly subtle: Someone may be calling the pymalloc
* free via PyMem_{DEL, Del, FREE, Free} without holding the * free via PyMem_{DEL, Del, FREE, Free} without holding the
@ -590,6 +590,7 @@ _PyMalloc_Malloc(size_t nbytes)
*/ */
++pool->ref.count; ++pool->ref.count;
bp = pool->freeblock; bp = pool->freeblock;
assert(bp != NULL);
if ((pool->freeblock = *(block **)bp) != NULL) { if ((pool->freeblock = *(block **)bp) != NULL) {
UNLOCK(); UNLOCK();
return (void *)bp; return (void *)bp;
@ -1057,12 +1058,15 @@ _PyMalloc_DebugRealloc(void *p, size_t nbytes)
return p; return p;
} }
assert(nbytes != 0);
/* More memory is needed: get it, copy over the first original_nbytes /* More memory is needed: get it, copy over the first original_nbytes
of the original data, and free the original memory. */ of the original data, and free the original memory. */
fresh = _PyMalloc_DebugMalloc(nbytes); fresh = _PyMalloc_DebugMalloc(nbytes);
if (fresh != NULL && original_nbytes > 0) if (fresh != NULL) {
memcpy(fresh, p, original_nbytes); if (original_nbytes > 0)
_PyMalloc_DebugFree(p); memcpy(fresh, p, original_nbytes);
_PyMalloc_DebugFree(p);
}
return fresh; return fresh;
} }