subtype_dealloc for heap types is a footgun
まだ誰も着手していません。
- 主要言語
- Python
- スター
- 77.2k
- フォーク
- 35.9k
- PR マージ指標
- PR 指標を取得中
説明
Bug report
Bug description:
#include <Python.h>
static PyType_Slot base_slots[] = {
{0, 0}
};
static PyType_Spec base_spec = {
.name = "Base",
.basicsize = 0,
.itemsize = 0,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.slots = base_slots,
};
static void derived_dealloc(PyObject *o) {
// call base class dealloc
destructor base_slot = PyType_GetSlot(Py_TYPE(o), Py_tp_dealloc);
base_slot(o);
}
static PyType_Slot derived_slots[] = {
{Py_tp_dealloc, derived_dealloc},
{0, 0}
};
static PyType_Spec derived_spec = {
.name = "Derived",
.basicsize = 0,
.itemsize = 0,
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.slots = derived_slots,
};
static int
deallocdemo_module_exec(PyObject *m)
{
PyObject *base_type = PyType_FromModuleAndSpec(
m,
&base_spec,
NULL
);
if (!base_type) return -1;
if (PyModule_AddObjectRef(m, "Base", base_type) < 0) {
Py_DECREF(base_type);
return -1;
}
PyObject *derived_type = PyType_FromModuleAndSpec(
m,
&derived_spec,
base_type
);
Py_DECREF(base_type);
if (!derived_type) return -1;
int add_object_res = PyModule_AddObjectRef(m, "Derived", derived_type);
Py_DECREF(derived_type);
return add_object_res;
}
static PyModuleDef_Slot deallocdemo_module_slots[] = {
{Py_mod_exec, deallocdemo_module_exec},
{0, NULL}
};
static struct PyModuleDef deallocdemo_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "deallocdemo",
.m_size = 0,
.m_slots = deallocdemo_module_slots,
};
PyMODINIT_FUNC
PyInit_deallocdemo(void)
{
return PyModuleDef_Init(&deallocdemo_module);
}
Essentially, subtype_dealloc prevents any derived type from implementing its own dealloc function. In the example above, trying to destroy a Derived object will cause an infinite loop because subtype_dealloc will call derived_dealloc (which calls subtype_dealloc).
This is something that works better for static-types, where the default was to inherit the tp_dealloc of the base class. I appreciate heap types are a little more complex in the inheritance they allow though.
I suspect this is now too late to change easily, and I can't personally think of any obvious solutions to it. It's obvious possible to work around (by creating a custom tp_dealloc at all levels) so the issue is more "it's a footgun" than "it's unworkable". But it seems worth raising the issue in case it can be improved somehow.
CPython versions tested on:
3.13
Operating systems tested on:
Linux
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
この再現プログラムは PyType_FromModuleAndSpec、PyType_GetSlot、Py_tp_dealloc、subtype_dealloc を使用しているため、まず CPython の型実装におけるこのデアロケーションパスを追跡します。提供された Base/Derived 拡張をリグレッションケースとして使用し、ヒープ型のデアロケータについて安全な動作を確立してテストします。この issue ではテストファイルは指定されておらず、解決策も規定されていません。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- c, python
- 領域
- backend-api-design
- issue の種類
- バグ
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- 説明が足りない
- 初心者へのやさしさ
- 30/100