10000 bpo-31626: Mark ends of the reallocated block in debug build. (#4210) · python/cpython@3cc4c53 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3cc4c53

Browse files
bpo-31626: Mark ends of the reallocated block in debug build. (#4210)
Few bytes at the begin and at the end of the reallocated blocks, as well as the header and the trailer, now are erased before calling realloc() in debug build. This will help to detect using or double freeing the reallocated block.
1 parent cb04f75 commit 3cc4c53

File tree

1 file changed

+57
-19
lines changed

1 file changed

+57
-19
lines changed

Objects/obmalloc.c

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,7 +1418,7 @@ static void *
14181418
_PyMem_DebugRawAlloc(int use_calloc, void *ctx, size_t nbytes)
14191419
{
14201420
debug_alloc_api_t *api = (debug_alloc_api_t *)ctx;
1421-
uint8_t *p; /* base address of malloc'epad d block */
1421+
uint8_t *p; /* base address of malloc'ed pad block */
14221422
uint8_t *data; /* p + 2*SST == pointer to data bytes */
14231423
uint8_t *tail; /* data + nbytes == pointer to tail pad bytes */
14241424
size_t total; /* 2 * SST + nbytes + 2 * SST */
@@ -1516,45 +1516,83 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
15161516
}
15171517

15181518
debug_alloc_api_t *api = (debug_alloc_api_t *)ctx;
1519-
uint8_t *q; /* base address of malloc'epad d block */
1520-
uint8_t *data; /* p + 2*SST == pointer to data bytes */
1519+
uint8_t *head; /* base address of malloc'ed pad block */
1520+
uint8_t *data; /* pointer to data bytes */
1521+
uint8_t *r;
15211522
uint8_t *tail; /* data + nbytes == pointer to tail pad bytes */
15221523
size_t total; /* 2 * SST + nbytes + 2 * SST */
15231524
size_t original_nbytes;
1524-
int i;
1525+
size_t se 10000 rialno;
1526+
#define ERASED_SIZE 64
1527+
uint8_t save[2*ERASED_SIZE]; /* A copy of erased bytes. */
15251528

15261529
_PyMem_DebugCheckAddress(api->api_id, p);
15271530

1528-
q = (uint8_t *)p;
1529-
original_nbytes = read_size_t(q - 2*SST);
1531+
data = (uint8_t *)p;
1532+
head = data - 2*SST;
1533+
original_nbytes = read_size_t(head);
15301534
if (nbytes > (size_t)PY_SSIZE_T_MAX - 4*SST) {
15311535
/* integer overflow: can't represent total as a Py_ssize_t */
15321536
return NULL;
15331537
}
15341538
total = nbytes + 4*SST;
15351539

1536-
/* Resize and add decorations. */
1537-
q = (uint8_t *)api->alloc.realloc(api->alloc.ctx, q - 2*SST, total);
1538-
if (q == NULL) {
1539-
return NULL;
1540+
tail = data + original_nbytes;
1541+
serialno = read_size_t(tail + SST);
1542+
/* Mark the header, the trailer, ERASED_SIZE bytes at the begin and
1543+
ERASED_SIZE bytes at the end as dead and save the copy of erased bytes.
1544+
*/
1545+
if (original_nbytes <= sizeof(save)) {
1546+
memcpy(save, data, original_nbytes);
1547+
memset(data - 2*SST, DEADBYTE, original_nbytes + 4*SST);
1548+
}
1549+
else {
1550+
memcpy(save, data, ERASED_SIZE);
1551+
memset(head, DEADBYTE, ERASED_SIZE + 2*SST);
1552+
memcpy(&save[ERASED_SIZE], tail - ERASED_SIZE, ERASED_SIZE);
1553+
memset(tail - ERASED_SIZE, DEADBYTE, ERASED_SIZE + 2*SST);
15401554
}
15411555

1542-
bumpserialno();
1543-
write_size_t(q, nbytes);
1544-
assert(q[SST] == (uint8_t)api->api_id);
1545-
for (i = 1; i < SST; ++i) {
1546-
assert(q[SST + i] == FORBIDDENBYTE);
1556+
/* Resize and add decorations. */
1557+
r = (uint8_t *)api->alloc.realloc(api->alloc.ctx, head, total);
1558+
if (r == NULL) {
1559+
nbytes = original_nbytes;
1560+
}
1561+
else {
1562+
head = r;
1563+
bumpserialno();
1564+
serialno = _PyRuntime.mem.serialno;
15471565
}
1548-
data = q + 2*SST;
1566+
1567+
write_size_t(head, nbytes);
1568+
head[SST] = (uint8_t)api->api_id;
1569+
memset(head + SST + 1, FORBIDDENBYTE, SST-1);
1570+
data = head + 2*SST;
15491571

15501572
tail = data + nbytes;
15511573
memset(tail, FORBIDDENBYTE, SST);
1552-
write_size_t(tail + SST, _PyRuntime.mem.serialno);
1574+
write_size_t(tail + SST, serialno);
1575+
1576+
/* Restore saved bytes. */
1577+
if (original_nbytes <= sizeof(save)) {
1578+
memcpy(data, save, Py_MIN(nbytes, original_nbytes));
1579+
}
1580+
else {
1581+
size_t i = original_nbytes - ERASED_SIZE;
1582+
memcpy(data, save, Py_MIN(nbytes, ERASED_SIZE));
1583+
if (nbytes > i) {
1584+
memcpy(data + i, &save[ERASED_SIZE],
1585+
Py_MIN(nbytes - i, ERASED_SIZE));
1586+
}
1587+
}
1588+
1589+
if (r == NULL) {
1590+
return NULL;
1591+
}
15531592

15541593
if (nbytes > original_nbytes) {
15551594
/* growing: mark new extra memory clean */
1556-
memset(data + original_nbytes, CLEANBYTE,
1557-
nbytes - original_nbytes);
1595+
memset(data + original_nbytes, CLEANBYTE, nbytes - original_nbytes);
15581596
}
15591597

15601598
return data;

0 commit comments

Comments
 (0)
0