Skip to content

Commit 347acde

Browse files
authored
gh-115491: Keep some fields valid across allocations in obmalloc (free-threading) (#115745)
1 parent 87a65a5 commit 347acde

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

Objects/object.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,13 @@ _Py_DecRef(PyObject *o)
299299

300300
#ifdef Py_GIL_DISABLED
301301
# ifdef Py_REF_DEBUG
302-
static inline int
303-
is_shared_refcnt_dead(Py_ssize_t shared)
302+
static int
303+
is_dead(PyObject *o)
304304
{
305305
# if SIZEOF_SIZE_T == 8
306-
return shared == (Py_ssize_t)0xDDDDDDDDDDDDDDDD;
306+
return (uintptr_t)o->ob_type == 0xDDDDDDDDDDDDDDDD;
307307
# else
308-
return shared == (Py_ssize_t)0xDDDDDDDD;
308+
return (uintptr_t)o->ob_type == 0xDDDDDDDD;
309309
# endif
310310
}
311311
# endif
@@ -335,8 +335,8 @@ _Py_DecRefSharedDebug(PyObject *o, const char *filename, int lineno)
335335
}
336336

337337
#ifdef Py_REF_DEBUG
338-
if ((_Py_REF_IS_MERGED(new_shared) && new_shared < 0) ||
339-
is_shared_refcnt_dead(shared))
338+
if ((new_shared < 0 && _Py_REF_IS_MERGED(new_shared)) ||
339+
(should_queue && is_dead(o)))
340340
{
341341
_Py_NegativeRefcount(filename, lineno, o);
342342
}

Objects/obmalloc.c

+27-4
Original file line numberDiff line numberDiff line change
@@ -2459,6 +2459,24 @@ write_size_t(void *p, size_t n)
24592459
}
24602460
}
24612461

2462+
static void
2463+
fill_mem_debug(debug_alloc_api_t *api, void *data, int c, size_t nbytes)
2464+
{
2465+
#ifdef Py_GIL_DISABLED
2466+
if (api->api_id == 'o') {
2467+
// Don't overwrite the first few bytes of a PyObject allocation in the
2468+
// free-threaded build
2469+
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *)_PyThreadState_GET();
2470+
size_t debug_offset = tstate->mimalloc.current_object_heap->debug_offset;
2471+
if (debug_offset < nbytes) {
2472+
memset((char *)data + debug_offset, c, nbytes - debug_offset);
2473+
}
2474+
return;
2475+
}
2476+
#endif
2477+
memset(data, c, nbytes);
2478+
}
2479+
24622480
/* Let S = sizeof(size_t). The debug malloc asks for 4 * S extra bytes and
24632481
fills them with useful stuff, here calling the underlying malloc's result p:
24642482
@@ -2535,7 +2553,7 @@ _PyMem_DebugRawAlloc(int use_calloc, void *ctx, size_t nbytes)
25352553
memset(p + SST + 1, PYMEM_FORBIDDENBYTE, SST-1);
25362554

25372555
if (nbytes > 0 && !use_calloc) {
2538-
memset(data, PYMEM_CLEANBYTE, nbytes);
2556+
fill_mem_debug(api, data, PYMEM_CLEANBYTE, nbytes);
25392557
}
25402558

25412559
/* at tail, write pad (SST bytes) and serialno (SST bytes) */
@@ -2583,8 +2601,9 @@ _PyMem_DebugRawFree(void *ctx, void *p)
25832601

25842602
_PyMem_DebugCheckAddress(__func__, api->api_id, p);
25852603
nbytes = read_size_t(q);
2586-
nbytes += PYMEM_DEBUG_EXTRA_BYTES;
2587-
memset(q, PYMEM_DEADBYTE, nbytes);
2604+
nbytes += PYMEM_DEBUG_EXTRA_BYTES - 2*SST;
2605+
memset(q, PYMEM_DEADBYTE, 2*SST);
2606+
fill_mem_debug(api, p, PYMEM_DEADBYTE, nbytes);
25882607
api->alloc.free(api->alloc.ctx, q);
25892608
}
25902609

@@ -2604,7 +2623,6 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
26042623
size_t total; /* 2 * SST + nbytes + 2 * SST */
26052624
size_t original_nbytes;
26062625
#define ERASED_SIZE 64
2607-
uint8_t save[2*ERASED_SIZE]; /* A copy of erased bytes. */
26082626

26092627
_PyMem_DebugCheckAddress(__func__, api->api_id, p);
26102628

@@ -2621,9 +2639,11 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
26212639
#ifdef PYMEM_DEBUG_SERIALNO
26222640
size_t block_serialno = read_size_t(tail + SST);
26232641
#endif
2642+
#ifndef Py_GIL_DISABLED
26242643
/* Mark the header, the trailer, ERASED_SIZE bytes at the begin and
26252644
ERASED_SIZE bytes at the end as dead and save the copy of erased bytes.
26262645
*/
2646+
uint8_t save[2*ERASED_SIZE]; /* A copy of erased bytes. */
26272647
if (original_nbytes <= sizeof(save)) {
26282648
memcpy(save, data, original_nbytes);
26292649
memset(data - 2 * SST, PYMEM_DEADBYTE,
@@ -2636,6 +2656,7 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
26362656
memset(tail - ERASED_SIZE, PYMEM_DEADBYTE,
26372657
ERASED_SIZE + PYMEM_DEBUG_EXTRA_BYTES - 2 * SST);
26382658
}
2659+
#endif
26392660

26402661
/* Resize and add decorations. */
26412662
r = (uint8_t *)api->alloc.realloc(api->alloc.ctx, head, total);
@@ -2663,6 +2684,7 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
26632684
write_size_t(tail + SST, block_serialno);
26642685
#endif
26652686

2687+
#ifndef Py_GIL_DISABLED
26662688
/* Restore saved bytes. */
26672689
if (original_nbytes <= sizeof(save)) {
26682690
memcpy(data, save, Py_MIN(nbytes, original_nbytes));
@@ -2675,6 +2697,7 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
26752697
Py_MIN(nbytes - i, ERASED_SIZE));
26762698
}
26772699
}
2700+
#endif
26782701

26792702
if (r == NULL) {
26802703
return NULL;

0 commit comments

Comments
 (0)