Skip to content

Commit 38965ec

Browse files
authored
bpo-39947: Hide implementation detail of trashcan macros (GH-18971)
Py_TRASHCAN_BEGIN_CONDITION and Py_TRASHCAN_END macro no longer access PyThreadState attributes, but call new private _PyTrash_begin() and _PyTrash_end() functions which hide implementation details.
1 parent 309d7cc commit 38965ec

File tree

3 files changed

+45
-15
lines changed

3 files changed

+45
-15
lines changed

Include/cpython/object.h

+18-15
Original file line numberDiff line numberDiff line change
@@ -385,11 +385,6 @@ PyAPI_DATA(PyTypeObject) _PyNotImplemented_Type;
385385
*/
386386
PyAPI_DATA(int) _Py_SwappedOp[];
387387

388-
/* This is the old private API, invoked by the macros before 3.2.4.
389-
Kept for binary compatibility of extensions using the stable ABI. */
390-
PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*);
391-
PyAPI_FUNC(void) _PyTrash_destroy_chain(void);
392-
393388
PyAPI_FUNC(void)
394389
_PyDebugAllocatorStats(FILE *out, const char *block_name, int num_blocks,
395390
size_t sizeof_block);
@@ -507,10 +502,23 @@ partially-deallocated object. To check this, the tp_dealloc function must be
507502
passed as second argument to Py_TRASHCAN_BEGIN().
508503
*/
509504

510-
/* The new thread-safe private API, invoked by the macros below. */
505+
/* This is the old private API, invoked by the macros before 3.2.4.
506+
Kept for binary compatibility of extensions using the stable ABI. */
507+
PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*);
508+
PyAPI_FUNC(void) _PyTrash_destroy_chain(void);
509+
510+
/* This is the old private API, invoked by the macros before 3.9.
511+
Kept for binary compatibility of extensions using the stable ABI. */
511512
PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyObject*);
512513
PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
513514

515+
/* Forward declarations for PyThreadState */
516+
struct _ts;
517+
518+
/* Python 3.9 private API, invoked by the macros below. */
519+
PyAPI_FUNC(int) _PyTrash_begin(struct _ts *tstate, PyObject *op);
520+
PyAPI_FUNC(void) _PyTrash_end(struct _ts *tstate);
521+
514522
#define PyTrash_UNWIND_LEVEL 50
515523

516524
#define Py_TRASHCAN_BEGIN_CONDITION(op, cond) \
@@ -520,24 +528,19 @@ PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(void);
520528
* is run normally without involving the trashcan */ \
521529
if (cond) { \
522530
_tstate = PyThreadState_GET(); \
523-
if (_tstate->trash_delete_nesting >= PyTrash_UNWIND_LEVEL) { \
524-
/* Store the object (to be deallocated later) and jump past \
525-
* Py_TRASHCAN_END, skipping the body of the deallocator */ \
526-
_PyTrash_thread_deposit_object(_PyObject_CAST(op)); \
531+
if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \
527532
break; \
528533
} \
529-
++_tstate->trash_delete_nesting; \
530534
}
531535
/* The body of the deallocator is here. */
532536
#define Py_TRASHCAN_END \
533537
if (_tstate) { \
534-
--_tstate->trash_delete_nesting; \
535-
if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \
536-
_PyTrash_thread_destroy_chain(); \
538+
_PyTrash_end(_tstate); \
537539
} \
538540
} while (0);
539541

540-
#define Py_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN_CONDITION(op, \
542+
#define Py_TRASHCAN_BEGIN(op, dealloc) \
543+
Py_TRASHCAN_BEGIN_CONDITION(op, \
541544
Py_TYPE(op)->tp_dealloc == (destructor)(dealloc))
542545

543546
/* For backwards compatibility, these macros enable the trashcan
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Py_TRASHCAN_BEGIN_CONDITION and Py_TRASHCAN_END macro no longer access
2+
PyThreadState attributes, but call new private _PyTrash_begin() and
3+
_PyTrash_end() functions which hide implementation details.

Objects/object.c

+24
Original file line numberDiff line numberDiff line change
@@ -2116,6 +2116,30 @@ _PyTrash_thread_destroy_chain(void)
21162116
}
21172117

21182118

2119+
int
2120+
_PyTrash_begin(PyThreadState *tstate, PyObject *op)
2121+
{
2122+
if (tstate->trash_delete_nesting >= PyTrash_UNWIND_LEVEL) {
2123+
/* Store the object (to be deallocated later) and jump past
2124+
* Py_TRASHCAN_END, skipping the body of the deallocator */
2125+
_PyTrash_thread_deposit_object(op);
2126+
return 1;
2127+
}
2128+
++tstate->trash_delete_nesting;
2129+
return 0;
2130+
}
2131+
2132+
2133+
void
2134+
_PyTrash_end(PyThreadState *tstate)
2135+
{
2136+
--tstate->trash_delete_nesting;
2137+
if (tstate->trash_delete_later && tstate->trash_delete_nesting <= 0) {
2138+
_PyTrash_thread_destroy_chain();
2139+
}
2140+
}
2141+
2142+
21192143
void _Py_NO_RETURN
21202144
_PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg,
21212145
const char *file, int line, const char *function)

0 commit comments

Comments
 (0)