Index: Include/objimpl.h =================================================================== --- Include/objimpl.h (revision 74649) +++ Include/objimpl.h (working copy) @@ -108,6 +108,13 @@ PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p); PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p); PyAPI_FUNC(void) _PyObject_DebugMallocStats(void); +PyAPI_FUNC(void *) _PyObject_DebugMallocId(int id, size_t nbytes); +PyAPI_FUNC(void *) _PyObject_DebugReallocId(int id, void *p, size_t nbytes); +PyAPI_FUNC(void) _PyObject_DebugFreeId(int id, void *p); +PyAPI_FUNC(void) _PyObject_DebugCheckAddressId(int id, const void *p); +PyAPI_FUNC(void *) _PyMem_DebugMalloc(size_t nbytes); +PyAPI_FUNC(void *) _PyMem_DebugRealloc(void *p, size_t nbytes); +PyAPI_FUNC(void) _PyMem_DebugFree(void *p); #define PyObject_MALLOC _PyObject_DebugMalloc #define PyObject_Malloc _PyObject_DebugMalloc #define PyObject_REALLOC _PyObject_DebugRealloc Index: Include/pymem.h =================================================================== --- Include/pymem.h (revision 74649) +++ Include/pymem.h (working copy) @@ -59,9 +59,9 @@ /* Macros. */ #ifdef PYMALLOC_DEBUG /* Redirect all memory operations to Python's debugging allocator. */ -#define PyMem_MALLOC PyObject_MALLOC -#define PyMem_REALLOC PyObject_REALLOC -#define PyMem_FREE PyObject_FREE +#define PyMem_MALLOC _PyMem_DebugMalloc +#define PyMem_REALLOC _PyMem_DebugRealloc +#define PyMem_FREE _PyMem_DebugFree #else /* ! PYMALLOC_DEBUG */ Index: Objects/obmalloc.c =================================================================== --- Objects/obmalloc.c (revision 74649) +++ Objects/obmalloc.c (working copy) @@ -1254,6 +1254,26 @@ #define SST SIZEOF_SIZE_T +/* merge in a single byte id to the high byte of the serial no and return */ +static size_t +idserialno(int id) +{ + + int shift = (SST-1)*8; + size_t mask = ~(((size_t)0xff) << shift); + return (serialno & mask) | ((size_t)(id & 0xff) << shift); +} +static int +idfromserialno(size_t *serial) +{ + size_t id; + int shift = (SST-1)*8; + size_t mask = ~(((size_t)0xff) << shift); + id = ((*serial) & (~mask))>>shift; + *serial &= mask; + return (int)id; +} + /* Read sizeof(size_t) bytes at p as a big-endian size_t. */ static size_t read_size_t(const void *p) @@ -1331,9 +1351,50 @@ instant at which this block was passed out. */ + +/* wrap PyMem api with id 0 */ void * +_PyMem_DebugMalloc(size_t nbytes) +{ + return _PyObject_DebugMallocId(0, nbytes); +} +void * +_PyMem_DebugRealloc(void *p, size_t nbytes) +{ + return _PyObject_DebugReallocId(0, p, nbytes); +} +void +_PyMem_DebugFree(void *p) +{ + _PyObject_DebugFreeId(0, p); +} + +/* wrap PyObject api with id 1 */ +void * _PyObject_DebugMalloc(size_t nbytes) { + return _PyObject_DebugMallocId(1, nbytes); +} +void * +_PyObject_DebugRealloc(void *p, size_t nbytes) +{ + return _PyObject_DebugReallocId(1, p, nbytes); +} +void +_PyObject_DebugFree(void *p) +{ + _PyObject_DebugFreeId(1, p); +} +void +_PyObject_DebugCheckAddress(void *p) +{ + _PyObject_DebugCheckAddressId(1, p); +} + + +void * +_PyObject_DebugMallocId(int id, size_t nbytes) +{ uchar *p; /* base address of malloc'ed block */ uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */ size_t total; /* nbytes + 4*SST */ @@ -1356,7 +1417,7 @@ tail = p + 2*SST + nbytes; memset(tail, FORBIDDENBYTE, SST); - write_size_t(tail + SST, serialno); + write_size_t(tail + SST, idserialno(id)); return p + 2*SST; } @@ -1367,14 +1428,14 @@ Then calls the underlying free. */ void -_PyObject_DebugFree(void *p) +_PyObject_DebugFreeId(int id, void *p) { uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ size_t nbytes; if (p == NULL) return; - _PyObject_DebugCheckAddress(p); + _PyObject_DebugCheckAddressId(id, p); nbytes = read_size_t(q); if (nbytes > 0) memset(q, DEADBYTE, nbytes); @@ -1382,7 +1443,7 @@ } void * -_PyObject_DebugRealloc(void *p, size_t nbytes) +_PyObject_DebugReallocId(int id, void *p, size_t nbytes) { uchar *q = (uchar *)p; uchar *tail; @@ -1391,9 +1452,9 @@ int i; if (p == NULL) - return _PyObject_DebugMalloc(nbytes); + return _PyObject_DebugMallocId(id, nbytes); - _PyObject_DebugCheckAddress(p); + _PyObject_DebugCheckAddressId(id, p); bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; @@ -1417,7 +1478,7 @@ q += 2*SST; tail = q + nbytes; memset(tail, FORBIDDENBYTE, SST); - write_size_t(tail + SST, serialno); + write_size_t(tail + SST, idserialno(id)); if (nbytes > original_nbytes) { /* growing: mark new extra memory clean */ @@ -1433,13 +1494,16 @@ * and call Py_FatalError to kill the program. */ void -_PyObject_DebugCheckAddress(const void *p) +_PyObject_DebugCheckAddressId(int id, const void *p) { const uchar *q = (const uchar *)p; + char msgbuf[64]; char *msg; size_t nbytes; const uchar *tail; int i; + size_t serial; + int id0; if (p == NULL) { msg = "didn't expect a NULL pointer"; @@ -1466,6 +1530,15 @@ } } + serial = read_size_t(tail+SST); + id0 = idfromserialno(&serial); + if (id0 != id) { + msg = msgbuf; + snprintf(msg, sizeof(msgbuf), "bad ID: Allocated using %d, verified using %d", id0, id); + msgbuf[sizeof(msgbuf)-1] = 0; + goto error; + } + return; error: @@ -1482,6 +1555,7 @@ size_t nbytes, serial; int i; int ok; + int id; fprintf(stderr, "Debug memory block at address p=%p:\n", p); if (p == NULL) @@ -1544,6 +1618,8 @@ } serial = read_size_t(tail + SST); + id = idfromserialno(&serial); + fprintf(stderr, "the block was allocated using id %d.\n", id); fprintf(stderr, " The block was made by call #%" PY_FORMAT_SIZE_T "u to debug malloc/realloc.\n", serial);