summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2002-04-12 08:52:50 (GMT)
committerTim Peters <tim.peters@gmail.com>2002-04-12 08:52:50 (GMT)
commit85cc1c43680ac0cf57269cdb594d5325ec07cf32 (patch)
tree95af5d26b08a32564dd51891df7d249302a5982a
parentf539c68ccd33ce140e5a15be3dcdbe4132d43948 (diff)
downloadcpython-85cc1c43680ac0cf57269cdb594d5325ec07cf32.zip
cpython-85cc1c43680ac0cf57269cdb594d5325ec07cf32.tar.gz
cpython-85cc1c43680ac0cf57269cdb594d5325ec07cf32.tar.bz2
_PyObject_DebugRealloc(): rewritten to let the underlying realloc do
most of the work. In particular, if the underlying realloc is able to grow the memory block in place, great (this routine used to do a fresh malloc + memcpy every time a block grew). BTW, I'm not so keen here on avoiding possible quadratic-time realloc patterns as I am on making the debug pymalloc more invisible (the more it uses memory "just like" the underlying allocator, the better the chance that a suspected memory corruption bug won't vanish when the debug malloc is turned on).
-rw-r--r--Objects/obmalloc.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index dcef1c5..66e0b7c 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -1005,46 +1005,49 @@ void *
_PyObject_DebugRealloc(void *p, size_t nbytes)
{
uchar *q = (uchar *)p;
+ uchar *tail;
+ size_t total; /* nbytes + 16 */
size_t original_nbytes;
- void *fresh; /* new memory block, if needed */
if (p == NULL)
return _PyObject_DebugMalloc(nbytes);
_PyObject_DebugCheckAddress(p);
+ bumpserialno();
original_nbytes = read4(q-8);
- if (nbytes == original_nbytes) {
- /* note that this case is likely to be common due to the
- way Python appends to lists */
- bumpserialno();
- write4(q + nbytes + 4, serialno);
- return p;
+ total = nbytes + 16;
+ if (total < nbytes || (total >> 31) > 1) {
+ /* overflow, or we can't represent it in 4 bytes */
+ return NULL;
}
if (nbytes < original_nbytes) {
- /* shrinking -- leave the guts alone, except to
- fill the excess with DEADBYTE */
- const size_t excess = original_nbytes - nbytes;
- bumpserialno();
- write4(q-8, nbytes);
- /* kill the excess bytes plus the trailing 8 pad bytes */
- q += nbytes;
- q[0] = q[1] = q[2] = q[3] = FORBIDDENBYTE;
- write4(q+4, serialno);
- memset(q+8, DEADBYTE, excess);
- return p;
+ /* shrinking: mark old extra memory dead */
+ memset(q + nbytes, DEADBYTE, original_nbytes - nbytes);
}
- assert(nbytes != 0);
- /* More memory is needed: get it, copy over the first original_nbytes
- of the original data, and free the original memory. */
- fresh = _PyObject_DebugMalloc(nbytes);
- if (fresh != NULL) {
- if (original_nbytes > 0)
- memcpy(fresh, p, original_nbytes);
- _PyObject_DebugFree(p);
+ /* Resize and add decorations. */
+ q = (uchar *)PyObject_Realloc(q-8, total);
+ if (q == NULL)
+ return NULL;
+
+ write4(q, nbytes);
+ assert(q[4] == FORBIDDENBYTE &&
+ q[5] == FORBIDDENBYTE &&
+ q[6] == FORBIDDENBYTE &&
+ q[7] == FORBIDDENBYTE);
+ q += 8;
+ tail = q + nbytes;
+ tail[0] = tail[1] = tail[2] = tail[3] = FORBIDDENBYTE;
+ write4(tail + 4, serialno);
+
+ if (nbytes > original_nbytes) {
+ /* growing: mark new extra memory clean */
+ memset(q + original_nbytes, CLEANBYTE,
+ nbytes - original_nbytes);
}
- return fresh;
+
+ return q;
}
/* Check the forbidden bytes on both ends of the memory allocated for p.