@@ -551,6 +551,14 @@ inline object get_python_state_dict() {
551551}
552552
553553// Get or create per-storage capsule in the current interpreter's state dict.
554+ // - The storage is interpreter-dependent: different interpreters will have different storage.
555+ // This is important when using multiple-interpreters, to avoid sharing unshareable objects
556+ // between interpreters.
557+ // - There is one storage per `key` in an interpreter and it is accessible between all extensions
558+ // in the same interpreter.
559+ // - The life span of the storage is tied to the interpreter: it will be kept alive until the
560+ // interpreter shuts down.
561+ //
554562// Use test-and-set pattern with `PyDict_SetDefault` for thread-safe concurrent access.
555563// WARNING: There can be multiple threads creating the storage at the same time, while only one
556564// will succeed in inserting its capsule into the dict. Therefore, the deleter will be
@@ -693,6 +701,11 @@ class internals_pp_manager {
693701 : holder_id_(id), on_fetch_(on_fetch) {}
694702
695703 std::unique_ptr<InternalsType> *get_or_create_pp_in_state_dict () {
704+ // The `unique_ptr<InternalsType>` output is leaked on interpreter shutdown. Once an
705+ // instance is created, it will never be deleted until the process exits (compare to
706+ // interpreter shutdown in multiple-interpreter scenarios).
707+ // Because we cannot guarantee the order of destruction of capsules in the interpreter
708+ // state dict, leaking avoids potential use-after-free issues during interpreter shutdown.
696709 auto *pp
697710 = atomic_get_or_create_in_state_dict<std::unique_ptr<InternalsType>,
698711 /* LeakOnInterpreterShutdown=*/ true >(holder_id_);
0 commit comments