/* Record that this arena_object slot is * available to be reused. */ ao->nextarena = unused_arena_objects; unused_arena_objects = ao; /* Free the entire arena. */ free((void *)ao->address); ao->address = 0; /* mark unassociated */ --narenas_currently_allocated; UNLOCK(); return; } if (nf == 1) { /* Case 2. Put ao at the head of * usable_arenas. Note that because * ao->nfreepools was 0 before, ao isn't * currently on the usable_arenas list. */ ao->nextarena = usable_arenas; ao->prevarena = NULL; if (usable_arenas) usable_arenas->prevarena = ao; usable_arenas = ao; assert(usable_arenas->address != 0); UNLOCK(); return; } /* If this arena is now out of order, we need to keep * the list sorted. The list is kept sorted so that * the "most full" arenas are used first, which allows * the nearly empty arenas to be completely freed. In * a few un-scientific tests, it seems like this * approach allowed a lot more memory to be freed. */ if (ao->nextarena == NULL || nf <= ao->nextarena->nfreepools) { /* Case 4. Nothing to do. */ UNLOCK(); return; } /* Case 3: We have to move the arena towards the end * of the list, because it has more free pools than * the arena to its right. * First unlink ao from usable_arenas. */ if (ao->prevarena != NULL) { /* ao isn't at the head of the list */ assert(ao->prevarena->nextarena == ao); ao->prevarena->nextarena = ao->nextarena; } else { /* ao is at the head of the list */ assert(usable_arenas == ao); usable_arenas = ao->nextarena; } ao->nextarena->prevarena = ao->prevarena; /* Locate the new insertion point by iterating over * the list, using our nextarena pointer. */ while (ao->nextarena != NULL && nf > ao->nextarena->nfreepools) { ao->prevarena = ao->nextarena; ao->nextarena = ao->nextarena->nextarena; } /* Insert ao at this point. */ assert(ao->nextarena == NULL || ao->prevarena == ao->nextarena->prevarena); assert(ao->prevarena->nextarena == ao->nextarena); ao->prevarena->nextarena = ao; if (ao->nextarena != NULL) ao->nextarena->prevarena = ao; /* Verify that the swaps worked. */ assert(ao->nextarena == NULL || nf <= ao->nextarena->nfreepools); assert(ao->prevarena == NULL || nf > ao->prevarena->nfreepools); assert(ao->nextarena == NULL || ao->nextarena->prevarena == ao); assert((usable_arenas == ao && ao->prevarena == NULL) || ao->prevarena->nextarena == ao); UNLOCK(); return; } /* Pool was full, so doesn't currently live in any list: * link it to the front of the appropriate usedpools[] list. * This mimics LRU pool usage for new allocations and * targets optimal filling when several pools contain * blocks of the same size class. */ --pool->ref.count; assert(pool->ref.count > 0); /* else the pool is empty */ size = pool->szidx; next = usedpools[size + size]; prev = next->prevpool; /* insert pool before next: prev <-> pool <-> next */ pool->nextpool = next; pool->prevpool = prev; next->prevpool = pool; prev->nextpool = pool; UNLOCK(); return; } /* We didn't allocate this address. */ free(p);} /* 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. */ #undef PyObject_Reallocvoid *PyObject_Realloc(void *p, size_t nbytes){ void *bp; poolp pool; size_t size; if (p == NULL) return PyObject_Malloc(nbytes); pool = POOL_ADDR(p); if (Py_ADDRESS_IN_RANGE(p, pool)) { /* We're in charge of this block */ size = INDEX2SIZE(pool->szidx); if (nbytes <= size) { /* The block is staying the same or shrinking. If * it's shrinking, there's a tradeoff: it costs * cycles to copy the block to a smaller size class, * but it wastes memory not to copy it. The * compromise here is to copy on shrink only if at * least 25% of size can be shaved off. */ if (4 * nbytes > 3 * size) { /* It's the same, * or shrinking and new/old > 3/4. */ return p; } size = nbytes; } bp = PyObject_Malloc(nbytes); if (bp != NULL) { memcpy(bp, p, size); PyObject_Free(p); } return bp; } /* We're not managing this block. If nbytes <= * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this * block. However, if we do, we need to copy the valid data from * the C-managed block to one of our blocks, and there's no portable * way to know how much of the memory space starting at p is valid. * As bug 1185883 pointed out the hard way, it's possible that the * C-managed block is "at the end" of allocated VM space, so that * a memory fault can occur if we try to copy nbytes bytes starting * at p. Instead we punt: let C continue to manage this block. */ if (nbytes) return realloc(p, nbytes); /* C doesn't define the result of realloc(p, 0) (it may or may not * return NULL then), but Python's docs promise that nbytes==0 never * returns NULL. We don't pass 0 to realloc(), to avoid that endcase * to begin with. Even then, we can't be sure that realloc() won't * return NULL. */ bp = realloc(p, 1); return bp ? bp : p;} #else /* ! WITH_PYMALLOC */ /*==========================================================================*//* pymalloc not enabled: Redirect the entry points to malloc. These will * only be used by extensions that are compiled with pymalloc enabled. */ void *PyObject_Malloc(size_t n){ return PyMem_MALLOC(n);} void *PyObject_Realloc(void *p, size_t n){ return PyMem_REALLOC(p, n);} voidPyObject_Free(void *p){ PyMem_FREE(p);}#endif /* WITH_PYMALLOC */ #ifdef PYMALLOC_DEBUG/*==========================================================================*//* A x-platform debugging allocator. This doesn't manage memory directly, * it wraps a real allocator, adding extra debugging info to the memory blocks. */ /* Special bytes broadcast into debug memory blocks at appropriate times. * Strings of these are unlikely to be valid addresses, floats, ints or * 7-bit ASCII. */#undef CLEANBYTE#undef DEADBYTE#undef FORBIDDENBYTE#define CLEANBYTE 0xCB /* clean (newly allocated) memory */#define DEADBYTE 0xDB /* dead (newly freed) memory */#define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */ static size_t serialno = 0; /* incremented on each debug {m,re}alloc */ /* serialno is always incremented via calling this routine. The point is * to supply a single place to set a breakpoint. */static voidbumpserialno(void){ ++serialno;} #define SST SIZEOF_SIZE_T /* Read sizeof(size_t) bytes at p as a big-endian size_t. */static size_tread_size_t(const void *p){ const uchar *q = (const uchar *)p; size_t result = *q++; int i; for (i = SST; --i > 0; ++q) result = (result << 8) | *q; return result;} /* Write n as a big-endian size_t, MSB at address p, LSB at * p + sizeof(size_t) - 1. */static voidwrite_size_t(void *p, size_t n){ uchar *q = (uchar *)p + SST - 1; int i; for (i = SST; --i >= 0; --q) { *q = (uchar)(n & 0xff); n >>= 8; }} #ifdef Py_DEBUG/* Is target in the list? The list is traversed via the nextpool pointers. * The list may be NULL-terminated, or circular. Return 1 if target is in * list, else 0. */static intpool_is_in_list(const poolp target, poolp list){ poolp origlist = list; assert(target != NULL); if (list == NULL) return 0; do { if (target == list) return 1; list = list->nextpool; } while (list != NULL && list != origlist); return 0;} #else#define pool_is_in_list(X, Y) 1 #endif /* Py_DEBUG */ /* Let S = sizeof(size_t). The debug malloc asks for 4*S extra bytes and fills them with useful stuff, here calling the underlying malloc's result p: p[0: S] Number of bytes originally asked for. This is a size_t, big-endian (easier to read in a memory dump).p[S: 2*S] Copies of FORBIDDENBYTE. Used to catch under- writes and reads.p[2*S: 2*S+n] The requested memory, filled with copies of CLEANBYTE. Used to catch reference to uninitialized memory. &p[2*S] is returned. Note that this is 8-byte aligned if pymalloc handled the request itself.p[2*S+n: 2*S+n+S] Copies of FORBIDDENBYTE. Used to catch over- writes and reads.p[2*S+n+S: 2*S+n+2*S] A serial number, incremented by 1 on each call to _PyObject_DebugMalloc and _PyObject_DebugRealloc. This is a big-endian size_t. If "bad memory" is detected later, the serial number gives an excellent way to set a breakpoint on the next run, to capture the instant at which this block was passed out.*/ void *_PyObject_DebugMalloc(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 */ bumpserialno(); total = nbytes + 4*SST; if (total < nbytes) /* overflow: can't represent total as a size_t */ return NULL; p = (uchar *)PyObject_Malloc(total); if (p == NULL) return NULL; write_size_t(p, nbytes); memset(p + SST, FORBIDDENBYTE, SST); if (nbytes > 0) memset(p + 2*SST, CLEANBYTE, nbytes); tail = p + 2*SST + nbytes; memset(tail, FORBIDDENBYTE, SST); write_size_t(tail + SST, serialno); return p + 2*SST;} /* The debug free first checks the 2*SST bytes on each end for sanity (in particular, that the FORBIDDENBYTEs are still intact). Then fills the original bytes with DEADBYTE. Then calls the underlying free.*/void_PyObject_DebugFree(void *p){ uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ size_t nbytes; if (p == NULL) return; _PyObject_DebugCheckAddress(p); nbytes = read_size_t(q); if (nbytes > 0) memset(q, DEADBYTE, nbytes); PyObject_Free(q);} void *_PyObject_DebugRealloc(void *p, size_t nbytes){ uchar *q = (uchar *)p; uchar *tail; size_t total; /* nbytes + 4*SST */ size_t original_nbytes; int i; if (p == NULL) return _PyObject_DebugMalloc(nbytes); _PyObject_DebugCheckAddress(p); bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; if (total < nbytes) /* overflow: can't represent total as a size_t */ return NULL; if (nbytes < original_nbytes) { /* shrinking: mark old extra memory dead */ memset(q + nbytes, DEADBYTE, original_nbytes - nbytes); } /* Resize and add decorations. */ q = (uchar *)PyObject_Realloc(q - 2*SST, total); if (q == NULL) return NULL; write_size_t(q, nbytes); for (i = 0; i < SST; ++i) assert(q[SST + i] == FORBIDDENBYTE); q += 2*SST; tail = q + nbytes; memset(tail, FORBIDDENBYTE, SST); write_size_t(tail + SST, serialno); if (nbytes > original_nbytes) { /* growing: mark new extra memory clean */ memset(q + original_nbytes, CLEANBYTE, nbytes - original_nbytes); } return q;} /* Check the forbidden bytes on both ends of the memory allocated for p. * If anything is wrong, print info to stderr via _PyObject_DebugDumpAddress, * and call Py_FatalError to kill the program. */ void_PyObject_DebugCheckAddress(const void *p){ const uchar *q = (const uchar *)p; char *msg; size_t nbytes; const uchar *tail; int i; if (p == NULL) { msg = "didn't expect a NULL pointer"; goto error; } /* Check the stuff at the start of p first: if there's underwrite * corruption, the number-of-bytes field may be nuts, and checking * the tail could lead to a segfault then. */ for (i = SST; i >= 1; --i) { if (*(q-i) != FORBIDDENBYTE) { msg = "bad leading pad byte"; goto error; } } nbytes = read_size_t(q - 2*SST); tail = q + nbytes; for (i = 0; i < SST; ++i) { if (tail[i] != FORBIDDENBYTE) { msg = "bad trailing pad byte"; goto error; } } return; error: _PyObject_DebugDumpAddress(p); Py_FatalError(msg);} /* Display info to stderr about the memory block at p. */void_PyObject_DebugDumpAddress(const void *p){ const uchar *q = (const uchar *)p; const uchar *tail; size_t nbytes, serial; int i; int ok; fprintf(stderr, "Debug memory block at address p=%p:\n", p); if (p == NULL) return; nbytes = read_size_t(q - 2*SST); fprintf(stderr, " %" PY_FORMAT_SIZE_T "u bytes originally " "requested\n", nbytes); /* In case this is nuts, check the leading pad bytes first. */ fprintf(stderr, " The %d pad bytes at p-%d are ", SST, SST); ok = 1; for (i = 1; i <= SST; ++i) { if (*(q-i) != FORBIDDENBYTE) { ok = 0; break; } } if (ok) fputs("FORBIDDENBYTE, as expected.\n", stderr); else { fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", FORBIDDENBYTE); for (i = SST; i >= 1; --i) { const uchar byte = *(q-i); fprintf(stderr, " at p-%d: 0x%02x", i, byte); if (byte != FORBIDDENBYTE) fputs(" *** OUCH", stderr); fputc('\n', stderr); } fputs(" Because memory is corrupted at the start, the " "count of bytes requested\n" " may be bogus, and checking the trailing pad " "bytes may segfault.\n", stderr); }Lines 1001–1500 of 1745. Previous lines Load more
/* Record that this arena_object slot is * available to be reused. */ ao->nextarena = unused_arena_objects; unused_arena_objects = ao; /* Free the entire arena. */ free((void *)ao->address); ao->address = 0; /* mark unassociated */ --narenas_currently_allocated; UNLOCK(); return; } if (nf == 1) { /* Case 2. Put ao at the head of * usable_arenas. Note that because * ao->nfreepools was 0 before, ao isn't * currently on the usable_arenas list. */ ao->nextarena = usable_arenas; ao->prevarena = NULL; if (usable_arenas) usable_arenas->prevarena = ao; usable_arenas = ao; assert(usable_arenas->address != 0); UNLOCK(); return; } /* If this arena is now out of order, we need to keep * the list sorted. The list is kept sorted so that * the "most full" arenas are used first, which allows * the nearly empty arenas to be completely freed. In * a few un-scientific tests, it seems like this * approach allowed a lot more memory to be freed. */ if (ao->nextarena == NULL || nf <= ao->nextarena->nfreepools) { /* Case 4. Nothing to do. */ UNLOCK(); return; } /* Case 3: We have to move the arena towards the end * of the list, because it has more free pools than * the arena to its right. * First unlink ao from usable_arenas. */ if (ao->prevarena != NULL) { /* ao isn't at the head of the list */ assert(ao->prevarena->nextarena == ao); ao->prevarena->nextarena = ao->nextarena; } else { /* ao is at the head of the list */ assert(usable_arenas == ao); usable_arenas = ao->nextarena; } ao->nextarena->prevarena = ao->prevarena; /* Locate the new insertion point by iterating over * the list, using our nextarena pointer. */ while (ao->nextarena != NULL && nf > ao->nextarena->nfreepools) { ao->prevarena = ao->nextarena; ao->nextarena = ao->nextarena->nextarena; } /* Insert ao at this point. */ assert(ao->nextarena == NULL || ao->prevarena == ao->nextarena->prevarena); assert(ao->prevarena->nextarena == ao->nextarena); ao->prevarena->nextarena = ao; if (ao->nextarena != NULL) ao->nextarena->prevarena = ao; /* Verify that the swaps worked. */ assert(ao->nextarena == NULL || nf <= ao->nextarena->nfreepools); assert(ao->prevarena == NULL || nf > ao->prevarena->nfreepools); assert(ao->nextarena == NULL || ao->nextarena->prevarena == ao); assert((usable_arenas == ao && ao->prevarena == NULL) || ao->prevarena->nextarena == ao); UNLOCK(); return; } /* Pool was full, so doesn't currently live in any list: * link it to the front of the appropriate usedpools[] list. * This mimics LRU pool usage for new allocations and * targets optimal filling when several pools contain * blocks of the same size class. */ --pool->ref.count; assert(pool->ref.count > 0); /* else the pool is empty */ size = pool->szidx; next = usedpools[size + size]; prev = next->prevpool; /* insert pool before next: prev <-> pool <-> next */ pool->nextpool = next; pool->prevpool = prev; next->prevpool = pool; prev->nextpool = pool; UNLOCK(); return; } /* We didn't allocate this address. */ free(p); } /* 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. */ #undef PyObject_Realloc void * PyObject_Realloc(void *p, size_t nbytes) { void *bp; poolp pool; size_t size; if (p == NULL) return PyObject_Malloc(nbytes); pool = POOL_ADDR(p); if (Py_ADDRESS_IN_RANGE(p, pool)) { /* We're in charge of this block */ size = INDEX2SIZE(pool->szidx); if (nbytes <= size) { /* The block is staying the same or shrinking. If * it's shrinking, there's a tradeoff: it costs * cycles to copy the block to a smaller size class, * but it wastes memory not to copy it. The * compromise here is to copy on shrink only if at * least 25% of size can be shaved off. */ if (4 * nbytes > 3 * size) { /* It's the same, * or shrinking and new/old > 3/4. */ return p; } size = nbytes; } bp = PyObject_Malloc(nbytes); if (bp != NULL) { memcpy(bp, p, size); PyObject_Free(p); } return bp; } /* We're not managing this block. If nbytes <= * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this * block. However, if we do, we need to copy the valid data from * the C-managed block to one of our blocks, and there's no portable * way to know how much of the memory space starting at p is valid. * As bug 1185883 pointed out the hard way, it's possible that the * C-managed block is "at the end" of allocated VM space, so that * a memory fault can occur if we try to copy nbytes bytes starting * at p. Instead we punt: let C continue to manage this block. */ if (nbytes) return realloc(p, nbytes); /* C doesn't define the result of realloc(p, 0) (it may or may not * return NULL then), but Python's docs promise that nbytes==0 never * returns NULL. We don't pass 0 to realloc(), to avoid that endcase * to begin with. Even then, we can't be sure that realloc() won't * return NULL. */ bp = realloc(p, 1); return bp ? bp : p; } #else /* ! WITH_PYMALLOC */ /*==========================================================================*/ /* pymalloc not enabled: Redirect the entry points to malloc. These will * only be used by extensions that are compiled with pymalloc enabled. */ void * PyObject_Malloc(size_t n) { return PyMem_MALLOC(n); } void * PyObject_Realloc(void *p, size_t n) { return PyMem_REALLOC(p, n); } void PyObject_Free(void *p) { PyMem_FREE(p); } #endif /* WITH_PYMALLOC */ #ifdef PYMALLOC_DEBUG /*==========================================================================*/ /* A x-platform debugging allocator. This doesn't manage memory directly, * it wraps a real allocator, adding extra debugging info to the memory blocks. */ /* Special bytes broadcast into debug memory blocks at appropriate times. * Strings of these are unlikely to be valid addresses, floats, ints or * 7-bit ASCII. */ #undef CLEANBYTE #undef DEADBYTE #undef FORBIDDENBYTE #define CLEANBYTE 0xCB /* clean (newly allocated) memory */ #define DEADBYTE 0xDB /* dead (newly freed) memory */ #define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */ static size_t serialno = 0; /* incremented on each debug {m,re}alloc */ /* serialno is always incremented via calling this routine. The point is * to supply a single place to set a breakpoint. */ static void bumpserialno(void) { ++serialno; } #define SST SIZEOF_SIZE_T /* Read sizeof(size_t) bytes at p as a big-endian size_t. */ static size_t read_size_t(const void *p) { const uchar *q = (const uchar *)p; size_t result = *q++; int i; for (i = SST; --i > 0; ++q) result = (result << 8) | *q; return result; } /* Write n as a big-endian size_t, MSB at address p, LSB at * p + sizeof(size_t) - 1. */ static void write_size_t(void *p, size_t n) { uchar *q = (uchar *)p + SST - 1; int i; for (i = SST; --i >= 0; --q) { *q = (uchar)(n & 0xff); n >>= 8; } } #ifdef Py_DEBUG /* Is target in the list? The list is traversed via the nextpool pointers. * The list may be NULL-terminated, or circular. Return 1 if target is in * list, else 0. */ static int pool_is_in_list(const poolp target, poolp list) { poolp origlist = list; assert(target != NULL); if (list == NULL) return 0; do { if (target == list) return 1; list = list->nextpool; } while (list != NULL && list != origlist); return 0; } #else #define pool_is_in_list(X, Y) 1 #endif /* Py_DEBUG */ /* Let S = sizeof(size_t). The debug malloc asks for 4*S extra bytes and fills them with useful stuff, here calling the underlying malloc's result p: p[0: S] Number of bytes originally asked for. This is a size_t, big-endian (easier to read in a memory dump). p[S: 2*S] Copies of FORBIDDENBYTE. Used to catch under- writes and reads. p[2*S: 2*S+n] The requested memory, filled with copies of CLEANBYTE. Used to catch reference to uninitialized memory. &p[2*S] is returned. Note that this is 8-byte aligned if pymalloc handled the request itself. p[2*S+n: 2*S+n+S] Copies of FORBIDDENBYTE. Used to catch over- writes and reads. p[2*S+n+S: 2*S+n+2*S] A serial number, incremented by 1 on each call to _PyObject_DebugMalloc and _PyObject_DebugRealloc. This is a big-endian size_t. If "bad memory" is detected later, the serial number gives an excellent way to set a breakpoint on the next run, to capture the instant at which this block was passed out. */ void * _PyObject_DebugMalloc(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 */ bumpserialno(); total = nbytes + 4*SST; if (total < nbytes) /* overflow: can't represent total as a size_t */ return NULL; p = (uchar *)PyObject_Malloc(total); if (p == NULL) return NULL; write_size_t(p, nbytes); memset(p + SST, FORBIDDENBYTE, SST); if (nbytes > 0) memset(p + 2*SST, CLEANBYTE, nbytes); tail = p + 2*SST + nbytes; memset(tail, FORBIDDENBYTE, SST); write_size_t(tail + SST, serialno); return p + 2*SST; } /* The debug free first checks the 2*SST bytes on each end for sanity (in particular, that the FORBIDDENBYTEs are still intact). Then fills the original bytes with DEADBYTE. Then calls the underlying free. */ void _PyObject_DebugFree(void *p) { uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ size_t nbytes; if (p == NULL) return; _PyObject_DebugCheckAddress(p); nbytes = read_size_t(q); if (nbytes > 0) memset(q, DEADBYTE, nbytes); PyObject_Free(q); } void * _PyObject_DebugRealloc(void *p, size_t nbytes) { uchar *q = (uchar *)p; uchar *tail; size_t total; /* nbytes + 4*SST */ size_t original_nbytes; int i; if (p == NULL) return _PyObject_DebugMalloc(nbytes); _PyObject_DebugCheckAddress(p); bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; if (total < nbytes) /* overflow: can't represent total as a size_t */ return NULL; if (nbytes < original_nbytes) { /* shrinking: mark old extra memory dead */ memset(q + nbytes, DEADBYTE, original_nbytes - nbytes); } /* Resize and add decorations. */ q = (uchar *)PyObject_Realloc(q - 2*SST, total); if (q == NULL) return NULL; write_size_t(q, nbytes); for (i = 0; i < SST; ++i) assert(q[SST + i] == FORBIDDENBYTE); q += 2*SST; tail = q + nbytes; memset(tail, FORBIDDENBYTE, SST); write_size_t(tail + SST, serialno); if (nbytes > original_nbytes) { /* growing: mark new extra memory clean */ memset(q + original_nbytes, CLEANBYTE, nbytes - original_nbytes); } return q; } /* Check the forbidden bytes on both ends of the memory allocated for p. * If anything is wrong, print info to stderr via _PyObject_DebugDumpAddress, * and call Py_FatalError to kill the program. */ void _PyObject_DebugCheckAddress(const void *p) { const uchar *q = (const uchar *)p; char *msg; size_t nbytes; const uchar *tail; int i; if (p == NULL) { msg = "didn't expect a NULL pointer"; goto error; } /* Check the stuff at the start of p first: if there's underwrite * corruption, the number-of-bytes field may be nuts, and checking * the tail could lead to a segfault then. */ for (i = SST; i >= 1; --i) { if (*(q-i) != FORBIDDENBYTE) { msg = "bad leading pad byte"; goto error; } } nbytes = read_size_t(q - 2*SST); tail = q + nbytes; for (i = 0; i < SST; ++i) { if (tail[i] != FORBIDDENBYTE) { msg = "bad trailing pad byte"; goto error; } } return; error: _PyObject_DebugDumpAddress(p); Py_FatalError(msg); } /* Display info to stderr about the memory block at p. */ void _PyObject_DebugDumpAddress(const void *p) { const uchar *q = (const uchar *)p; const uchar *tail; size_t nbytes, serial; int i; int ok; fprintf(stderr, "Debug memory block at address p=%p:\n", p); if (p == NULL) return; nbytes = read_size_t(q - 2*SST); fprintf(stderr, " %" PY_FORMAT_SIZE_T "u bytes originally " "requested\n", nbytes); /* In case this is nuts, check the leading pad bytes first. */ fprintf(stderr, " The %d pad bytes at p-%d are ", SST, SST); ok = 1; for (i = 1; i <= SST; ++i) { if (*(q-i) != FORBIDDENBYTE) { ok = 0; break; } } if (ok) fputs("FORBIDDENBYTE, as expected.\n", stderr); else { fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", FORBIDDENBYTE); for (i = SST; i >= 1; --i) { const uchar byte = *(q-i); fprintf(stderr, " at p-%d: 0x%02x", i, byte); if (byte != FORBIDDENBYTE) fputs(" *** OUCH", stderr); fputc('\n', stderr); } fputs(" Because memory is corrupted at the start, the " "count of bytes requested\n" " may be bogus, and checking the trailing pad " "bytes may segfault.\n", stderr); }