Skip to content

Commit ae4cfb1

Browse files
author
Kristján Valur Jónsson
committed
http://bugs.python.org/issue6836
Merging revisions 75103,75104 from trunk to py3k
1 parent 847ec75 commit ae4cfb1

4 files changed

Lines changed: 108 additions & 23 deletions

File tree

Include/objimpl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ PyAPI_FUNC(void) _PyObject_DebugFree(void *p);
108108
PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p);
109109
PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p);
110110
PyAPI_FUNC(void) _PyObject_DebugMallocStats(void);
111+
PyAPI_FUNC(void *) _PyObject_DebugMallocApi(char api, size_t nbytes);
112+
PyAPI_FUNC(void *) _PyObject_DebugReallocApi(char api, void *p, size_t nbytes);
113+
PyAPI_FUNC(void) _PyObject_DebugFreeApi(char api, void *p);
114+
PyAPI_FUNC(void) _PyObject_DebugCheckAddressApi(char api, const void *p);
115+
PyAPI_FUNC(void *) _PyMem_DebugMalloc(size_t nbytes);
116+
PyAPI_FUNC(void *) _PyMem_DebugRealloc(void *p, size_t nbytes);
117+
PyAPI_FUNC(void) _PyMem_DebugFree(void *p);
111118
#define PyObject_MALLOC _PyObject_DebugMalloc
112119
#define PyObject_Malloc _PyObject_DebugMalloc
113120
#define PyObject_REALLOC _PyObject_DebugRealloc

Include/pymem.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ PyAPI_FUNC(void) PyMem_Free(void *);
5959
/* Macros. */
6060
#ifdef PYMALLOC_DEBUG
6161
/* Redirect all memory operations to Python's debugging allocator. */
62-
#define PyMem_MALLOC PyObject_MALLOC
63-
#define PyMem_REALLOC PyObject_REALLOC
64-
#define PyMem_FREE PyObject_FREE
62+
#define PyMem_MALLOC _PyMem_DebugMalloc
63+
#define PyMem_REALLOC _PyMem_DebugRealloc
64+
#define PyMem_FREE _PyMem_DebugFree
6565

6666
#else /* ! PYMALLOC_DEBUG */
6767

Objects/obmalloc.c

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,10 @@ PyObject_Free(void *p)
12411241
#define DEADBYTE 0xDB /* dead (newly freed) memory */
12421242
#define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */
12431243

1244+
/* We tag each block with an API ID in order to tag API violations */
1245+
#define _PYMALLOC_MEM_ID 'm' /* the PyMem_Malloc() API */
1246+
#define _PYMALLOC_OBJ_ID 'o' /* The PyObject_Malloc() API */
1247+
12441248
static size_t serialno = 0; /* incremented on each debug {m,re}alloc */
12451249

12461250
/* serialno is always incremented via calling this routine. The point is
@@ -1331,8 +1335,49 @@ p[2*S+n+S: 2*S+n+2*S]
13311335
instant at which this block was passed out.
13321336
*/
13331337

1338+
/* debug replacements for the PyMem_* memory API */
1339+
void *
1340+
_PyMem_DebugMalloc(size_t nbytes)
1341+
{
1342+
return _PyObject_DebugMallocApi(_PYMALLOC_MEM_ID, nbytes);
1343+
}
1344+
void *
1345+
_PyMem_DebugRealloc(void *p, size_t nbytes)
1346+
{
1347+
return _PyObject_DebugReallocApi(_PYMALLOC_MEM_ID, p, nbytes);
1348+
}
1349+
void
1350+
_PyMem_DebugFree(void *p)
1351+
{
1352+
_PyObject_DebugFreeApi(_PYMALLOC_MEM_ID, p);
1353+
}
1354+
1355+
/* debug replacements for the PyObject_* memory API */
13341356
void *
13351357
_PyObject_DebugMalloc(size_t nbytes)
1358+
{
1359+
return _PyObject_DebugMallocApi(_PYMALLOC_OBJ_ID, nbytes);
1360+
}
1361+
void *
1362+
_PyObject_DebugRealloc(void *p, size_t nbytes)
1363+
{
1364+
return _PyObject_DebugReallocApi(_PYMALLOC_OBJ_ID, p, nbytes);
1365+
}
1366+
void
1367+
_PyObject_DebugFree(void *p)
1368+
{
1369+
_PyObject_DebugFreeApi(_PYMALLOC_OBJ_ID, p);
1370+
}
1371+
void
1372+
_PyObject_DebugCheckAddress(void *p)
1373+
{
1374+
_PyObject_DebugCheckAddressApi(_PYMALLOC_OBJ_ID, p);
1375+
}
1376+
1377+
1378+
/* generic debug memory api, with an "id" to identify the API in use */
1379+
void *
1380+
_PyObject_DebugMallocApi(char id, size_t nbytes)
13361381
{
13371382
uchar *p; /* base address of malloc'ed block */
13381383
uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */
@@ -1348,12 +1393,15 @@ _PyObject_DebugMalloc(size_t nbytes)
13481393
if (p == NULL)
13491394
return NULL;
13501395

1396+
/* at p, write size (SST bytes), id (1 byte), pad (SST-1 bytes) */
13511397
write_size_t(p, nbytes);
1352-
memset(p + SST, FORBIDDENBYTE, SST);
1398+
p[SST] = (uchar)id;
1399+
memset(p + SST + 1 , FORBIDDENBYTE, SST-1);
13531400

13541401
if (nbytes > 0)
13551402
memset(p + 2*SST, CLEANBYTE, nbytes);
13561403

1404+
/* at tail, write pad (SST bytes) and serialno (SST bytes) */
13571405
tail = p + 2*SST + nbytes;
13581406
memset(tail, FORBIDDENBYTE, SST);
13591407
write_size_t(tail + SST, serialno);
@@ -1362,27 +1410,28 @@ _PyObject_DebugMalloc(size_t nbytes)
13621410
}
13631411

13641412
/* The debug free first checks the 2*SST bytes on each end for sanity (in
1365-
particular, that the FORBIDDENBYTEs are still intact).
1413+
particular, that the FORBIDDENBYTEs with the api ID are still intact).
13661414
Then fills the original bytes with DEADBYTE.
13671415
Then calls the underlying free.
13681416
*/
13691417
void
1370-
_PyObject_DebugFree(void *p)
1418+
_PyObject_DebugFreeApi(char api, void *p)
13711419
{
13721420
uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */
13731421
size_t nbytes;
13741422

13751423
if (p == NULL)
13761424
return;
1377-
_PyObject_DebugCheckAddress(p);
1425+
_PyObject_DebugCheckAddressApi(api, p);
13781426
nbytes = read_size_t(q);
1427+
nbytes += 4*SST;
13791428
if (nbytes > 0)
13801429
memset(q, DEADBYTE, nbytes);
13811430
PyObject_Free(q);
13821431
}
13831432

13841433
void *
1385-
_PyObject_DebugRealloc(void *p, size_t nbytes)
1434+
_PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
13861435
{
13871436
uchar *q = (uchar *)p;
13881437
uchar *tail;
@@ -1391,9 +1440,9 @@ _PyObject_DebugRealloc(void *p, size_t nbytes)
13911440
int i;
13921441

13931442
if (p == NULL)
1394-
return _PyObject_DebugMalloc(nbytes);
1443+
return _PyObject_DebugMallocApi(api, nbytes);
13951444

1396-
_PyObject_DebugCheckAddress(p);
1445+
_PyObject_DebugCheckAddressApi(api, p);
13971446
bumpserialno();
13981447
original_nbytes = read_size_t(q - 2*SST);
13991448
total = nbytes + 4*SST;
@@ -1403,16 +1452,20 @@ _PyObject_DebugRealloc(void *p, size_t nbytes)
14031452

14041453
if (nbytes < original_nbytes) {
14051454
/* shrinking: mark old extra memory dead */
1406-
memset(q + nbytes, DEADBYTE, original_nbytes - nbytes);
1455+
memset(q + nbytes, DEADBYTE, original_nbytes - nbytes + 2*SST);
14071456
}
14081457

1409-
/* Resize and add decorations. */
1458+
/* Resize and add decorations. We may get a new pointer here, in which
1459+
* case we didn't get the chance to mark the old memory with DEADBYTE,
1460+
* but we live with that.
1461+
*/
14101462
q = (uchar *)PyObject_Realloc(q - 2*SST, total);
14111463
if (q == NULL)
14121464
return NULL;
14131465

14141466
write_size_t(q, nbytes);
1415-
for (i = 0; i < SST; ++i)
1467+
assert(q[SST] == (uchar)api);
1468+
for (i = 1; i < SST; ++i)
14161469
assert(q[SST + i] == FORBIDDENBYTE);
14171470
q += 2*SST;
14181471
tail = q + nbytes;
@@ -1431,26 +1484,38 @@ _PyObject_DebugRealloc(void *p, size_t nbytes)
14311484
/* Check the forbidden bytes on both ends of the memory allocated for p.
14321485
* If anything is wrong, print info to stderr via _PyObject_DebugDumpAddress,
14331486
* and call Py_FatalError to kill the program.
1487+
* The API id, is also checked.
14341488
*/
14351489
void
1436-
_PyObject_DebugCheckAddress(const void *p)
1490+
_PyObject_DebugCheckAddressApi(char api, const void *p)
14371491
{
14381492
const uchar *q = (const uchar *)p;
1493+
char msgbuf[64];
14391494
char *msg;
14401495
size_t nbytes;
14411496
const uchar *tail;
14421497
int i;
1498+
char id;
14431499

14441500
if (p == NULL) {
14451501
msg = "didn't expect a NULL pointer";
14461502
goto error;
14471503
}
14481504

1505+
/* Check the API id */
1506+
id = (char)q[-SST];
1507+
if (id != api) {
1508+
msg = msgbuf;
1509+
snprintf(msg, sizeof(msgbuf), "bad ID: Allocated using API '%c', verified using API '%c'", id, api);
1510+
msgbuf[sizeof(msgbuf)-1] = 0;
1511+
goto error;
1512+
}
1513+
14491514
/* Check the stuff at the start of p first: if there's underwrite
14501515
* corruption, the number-of-bytes field may be nuts, and checking
14511516
* the tail could lead to a segfault then.
14521517
*/
1453-
for (i = SST; i >= 1; --i) {
1518+
for (i = SST-1; i >= 1; --i) {
14541519
if (*(q-i) != FORBIDDENBYTE) {
14551520
msg = "bad leading pad byte";
14561521
goto error;
@@ -1482,19 +1547,24 @@ _PyObject_DebugDumpAddress(const void *p)
14821547
size_t nbytes, serial;
14831548
int i;
14841549
int ok;
1550+
char id;
14851551

1486-
fprintf(stderr, "Debug memory block at address p=%p:\n", p);
1487-
if (p == NULL)
1552+
fprintf(stderr, "Debug memory block at address p=%p:", p);
1553+
if (p == NULL) {
1554+
fprintf(stderr, "\n");
14881555
return;
1556+
}
1557+
id = (char)q[-SST];
1558+
fprintf(stderr, " API '%c'\n", id);
14891559

14901560
nbytes = read_size_t(q - 2*SST);
14911561
fprintf(stderr, " %" PY_FORMAT_SIZE_T "u bytes originally "
14921562
"requested\n", nbytes);
14931563

14941564
/* In case this is nuts, check the leading pad bytes first. */
1495-
fprintf(stderr, " The %d pad bytes at p-%d are ", SST, SST);
1565+
fprintf(stderr, " The %d pad bytes at p-%d are ", SST-1, SST-1);
14961566
ok = 1;
1497-
for (i = 1; i <= SST; ++i) {
1567+
for (i = 1; i <= SST-1; ++i) {
14981568
if (*(q-i) != FORBIDDENBYTE) {
14991569
ok = 0;
15001570
break;
@@ -1505,7 +1575,7 @@ _PyObject_DebugDumpAddress(const void *p)
15051575
else {
15061576
fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n",
15071577
FORBIDDENBYTE);
1508-
for (i = SST; i >= 1; --i) {
1578+
for (i = SST-1; i >= 1; --i) {
15091579
const uchar byte = *(q-i);
15101580
fprintf(stderr, " at p-%d: 0x%02x", i, byte);
15111581
if (byte != FORBIDDENBYTE)

Parser/parsetok.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,16 +240,24 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
240240
}
241241
}
242242
} else if (tok->encoding != NULL) {
243+
/* 'nodes->n_str' uses PyObject_*, while 'tok->encoding' was
244+
* allocated using PyMem_
245+
*/
243246
node* r = PyNode_New(encoding_decl);
244-
if (!r) {
247+
if (r)
248+
r->n_str = PyObject_MALLOC(strlen(tok->encoding)+1);
249+
if (!r || !r->n_str) {
245250
err_ret->error = E_NOMEM;
251+
if (r)
252+
PyObject_FREE(r);
246253
n = NULL;
247254
goto done;
248255
}
249-
r->n_str = tok->encoding;
256+
strcpy(r->n_str, tok->encoding);
257+
PyMem_FREE(tok->encoding);
258+
tok->encoding = NULL;
250259
r->n_nchildren = 1;
251260
r->n_child = n;
252-
tok->encoding = NULL;
253261
n = r;
254262
}
255263

0 commit comments

Comments
 (0)