@@ -429,81 +429,14 @@ PyAPI_FUNC(void) _Py_NO_RETURN _PyObject_AssertFailed(
429
429
const char * function );
430
430
431
431
432
- /* Trashcan mechanism, thanks to Christian Tismer.
433
-
434
- When deallocating a container object, it's possible to trigger an unbounded
435
- chain of deallocations, as each Py_DECREF in turn drops the refcount on "the
436
- next" object in the chain to 0. This can easily lead to stack overflows,
437
- especially in threads (which typically have less stack space to work with).
438
-
439
- A container object can avoid this by bracketing the body of its tp_dealloc
440
- function with a pair of macros:
441
-
442
- static void
443
- mytype_dealloc(mytype *p)
444
- {
445
- ... declarations go here ...
446
-
447
- PyObject_GC_UnTrack(p); // must untrack first
448
- Py_TRASHCAN_BEGIN(p, mytype_dealloc)
449
- ... The body of the deallocator goes here, including all calls ...
450
- ... to Py_DECREF on contained objects. ...
451
- Py_TRASHCAN_END // there should be no code after this
452
- }
453
-
454
- CAUTION: Never return from the middle of the body! If the body needs to
455
- "get out early", put a label immediately before the Py_TRASHCAN_END
456
- call, and goto it. Else the call-depth counter (see below) will stay
457
- above 0 forever, and the trashcan will never get emptied.
458
-
459
- How it works: The BEGIN macro increments a call-depth counter. So long
460
- as this counter is small, the body of the deallocator is run directly without
461
- further ado. But if the counter gets large, it instead adds p to a list of
462
- objects to be deallocated later, skips the body of the deallocator, and
463
- resumes execution after the END macro. The tp_dealloc routine then returns
464
- without deallocating anything (and so unbounded call-stack depth is avoided).
465
-
466
- When the call stack finishes unwinding again, code generated by the END macro
467
- notices this, and calls another routine to deallocate all the objects that
468
- may have been added to the list of deferred deallocations. In effect, a
469
- chain of N deallocations is broken into (N-1)/(Py_TRASHCAN_HEADROOM-1) pieces,
470
- with the call stack never exceeding a depth of Py_TRASHCAN_HEADROOM.
471
-
472
- Since the tp_dealloc of a subclass typically calls the tp_dealloc of the base
473
- class, we need to ensure that the trashcan is only triggered on the tp_dealloc
474
- of the actual class being deallocated. Otherwise we might end up with a
475
- partially-deallocated object. To check this, the tp_dealloc function must be
476
- passed as second argument to Py_TRASHCAN_BEGIN().
477
- */
478
-
479
-
480
432
PyAPI_FUNC (void ) _PyTrash_thread_deposit_object (PyThreadState * tstate , PyObject * op );
481
433
PyAPI_FUNC (void ) _PyTrash_thread_destroy_chain (PyThreadState * tstate );
482
434
483
-
484
- /* Python 3.10 private API, invoked by the Py_TRASHCAN_BEGIN(). */
485
-
486
- /* To avoid raising recursion errors during dealloc trigger trashcan before we reach
487
- * recursion limit. To avoid trashing, we don't attempt to empty the trashcan until
488
- * we have headroom above the trigger limit */
489
- #define Py_TRASHCAN_HEADROOM 50
490
-
491
- /* Helper function for Py_TRASHCAN_BEGIN */
492
435
PyAPI_FUNC (int ) _Py_ReachedRecursionLimitWithMargin (PyThreadState * tstate , int margin_count );
493
436
494
- #define Py_TRASHCAN_BEGIN (op , dealloc ) \
495
- do { \
496
- PyThreadState *tstate = PyThreadState_Get(); \
497
- if (_Py_ReachedRecursionLimitWithMargin(tstate, 2) && Py_TYPE(op)->tp_dealloc == (destructor)dealloc) { \
498
- _PyTrash_thread_deposit_object(tstate, (PyObject *)op); \
499
- break; \
500
- }
501
- /* The body of the deallocator is here. */
502
- #define Py_TRASHCAN_END \
503
- if (tstate->delete_later && !_Py_ReachedRecursionLimitWithMargin(tstate, 4)) { \
504
- _PyTrash_thread_destroy_chain(tstate); \
505
- } \
506
- } while (0);
437
+ /* For backwards compatibility with the old trashcan mechanism */
438
+ #define Py_TRASHCAN_BEGIN (op , dealloc )
439
+ #define Py_TRASHCAN_END
507
440
508
441
509
442
PyAPI_FUNC (void * ) PyObject_GetItemData (PyObject * obj );
0 commit comments