8000 bpo-31626: Fix _PyObject_DebugReallocApi() (#4310) · python/cpython@ed4743a · GitHub
[go: up one dir, main page]

Skip to content

Commit ed4743a

Browse files
authored
bpo-31626: Fix _PyObject_DebugReallocApi() (#4310)
_PyObject_DebugReallocApi() now calls Py_FatalError() if realloc() fails to shrink a memory block. Call Py_FatalError() because _PyObject_DebugReallocApi() erased freed bytes *before* realloc(), expecting that realloc() *cannot* fail to shrink a memory block.
1 parent 35d9983 commit ed4743a

File tree

2 files changed

+16
-7
lines changed

2 files changed

+16
-7
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When Python is built in debug mode, the memory debug hooks now fail with a
2+
fatal error if realloc() fails to shrink a memory block, because the debug
3+
hook just erased freed bytes without keeping a copy of them.

Objects/obmalloc.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ static int running_on_valgrind = -1;
101101
*
102102
* For small requests, the allocator sub-allocates <Big> blocks of memory.
103103
* Requests greater than SMALL_REQUEST_THRESHOLD bytes are routed to the
104-
* system's allocator.
104+
* system's allocator.
105105
*
106106
* Small requests are grouped in size classes spaced 8 bytes apart, due
107107
* to the required valid alignment of the returned address. Requests of
@@ -134,7 +134,7 @@ static int running_on_valgrind = -1;
134134
* 65-72 72 8
135135
* ... ... ...
136136
* 497-504 504 62
137-
* 505-512 512 63
137+
* 505-512 512 63
138138
*
139139
* 0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying
140140
* allocator.
@@ -176,7 +176,7 @@ static int running_on_valgrind = -1;
176176
* Although not required, for better performance and space efficiency,
177177
* it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2.
178178
*/
179-
#define SMALL_REQUEST_THRESHOLD 512
179+
#define SMALL_REQUEST_THRESHOLD 512
180180
#define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT)
181181

182182
/*
@@ -209,7 +209,7 @@ static int running_on_valgrind = -1;
209209
* usually an address range reservation for <Big> bytes, unless all pages within
210210
* this space are referenced subsequently. So malloc'ing big blocks and not
211211
* using them does not mean "wasting memory". It's an addressable range
212-
* wastage...
212+
* wastage...
213213
*
214214
* Arenas are allocated with mmap() on systems supporting anonymous memory
215215
* mappings to reduce heap fragmentation.
@@ -619,7 +619,7 @@ new_arena(void)
619619
#else
620620
address = malloc(ARENA_SIZE);
621621
err = (address == 0);
622-
#endif
622+
#endif
623623
if (err) {
624624
/* The allocation failed: return NULL after putting the
625625
* arenaobj back.
@@ -1552,7 +1552,7 @@ _PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
15521552
/* overflow: can't represent total as a size_t */
15531553
return NULL;
15541554

1555-
if (nbytes < original_nbytes) {
1555+
if (nbytes <= original_nbytes) {
15561556
/* shrinking: mark old extra memory dead */
15571557
memset(q + nbytes, DEADBYTE, original_nbytes - nbytes + 2*SST);
15581558
}
@@ -1562,8 +1562,14 @@ _PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
15621562
* but we live with that.
15631563
*/
15641564
q = (uchar *)PyObject_Realloc(q - 2*SST, total);
1565-
if (q == NULL)
1565+
if (q == NULL) {
1566+
if (nbytes <= original_nbytes) {
1567+
/* bpo-31626: the memset() above expects that realloc never fails
1568+
on shrinking a memory block. */
1569+
Py_FatalError("Shrinking reallocation failed");
1570+
}
15661571
return NULL;
1572+
}
15671573

15681574
write_size_t(q, nbytes);
15691575
assert(q[SST] == (uchar)api);

0 commit comments

Comments
 (0)
0