aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2023-10-08 18:20:39 +0200
committerChristian Tismer <tismer@stackless.com>2023-10-09 11:32:10 +0200
commit8b9d69fac87cb18777e33103512c8592edd05ff4 (patch)
treeb862eb3fc03a5d4a4fe87087eeff839c8ad83803
parent65ac5d41a68dac51f85976e22ad2379d659f2f8e (diff)
shiboken: Get rid of tp_dict in general
It is a long due task to finally remove the direct access to type object fields. With Python 3.12, direct access to tp_dict became problematic. We use that as a reason to start removing the direct access in favor of function calls. Task-number: PYSIDE-2230 Change-Id: I6f8a7479ab0afdbef14d4661f66c3588f3a578aa Pick-to: 6.2 6.5 6.6 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.cpp6
-rw-r--r--sources/pyside6/libpyside/feature_select.cpp40
-rw-r--r--sources/pyside6/libpyside/pysidesignal.cpp3
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_container.cpp3
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp3
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp6
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.cpp12
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.h4
-rw-r--r--sources/shiboken6/libshiboken/sbkcontainer.cpp6
-rw-r--r--sources/shiboken6/libshiboken/sbkenum.cpp8
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp15
-rw-r--r--sources/shiboken6/libshiboken/sbktypefactory.cpp7
12 files changed, 74 insertions, 39 deletions
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
index 691e66ddc..b7fbc7661 100644
--- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
@@ -585,7 +585,8 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
// Leave the properties to be registered after signals because they may depend on
// notify signals.
for (PyTypeObject *baseType : basesToCheck) {
- PyObject *attrs = baseType->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(baseType));
+ PyObject *attrs = tpDict.object();
PyObject *key = nullptr;
PyObject *value = nullptr;
Py_ssize_t pos = 0;
@@ -617,7 +618,8 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
// Signals and slots should be separated, unless the types are modified, later.
// We check for this using "is_sorted()". Sorting no longer happens at all.
for (PyTypeObject *baseType : basesToCheck) {
- PyObject *attrs = baseType->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(baseType));
+ PyObject *attrs = tpDict.object();
PyObject *key = nullptr;
PyObject *value = nullptr;
Py_ssize_t pos = 0;
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp
index ec15e6d0a..3f8e38870 100644
--- a/sources/pyside6/libpyside/feature_select.cpp
+++ b/sources/pyside6/libpyside/feature_select.cpp
@@ -162,7 +162,7 @@ static bool replaceClassDict(PyTypeObject *type)
* This is mandatory for all type dicts when they are touched.
*/
ensureNewDictType();
- auto *dict = type->tp_dict;
+ AutoDecRef dict(PepType_GetDict(type));
auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
if (new_dict == nullptr || PyDict_Update(new_dict, dict) < 0)
@@ -173,8 +173,8 @@ static bool replaceClassDict(PyTypeObject *type)
setNextDict(new_dict, new_dict);
// We have now an exact copy of the dict with a new type.
// Replace `__dict__` which usually has refcount 1 (but see cyclic_test.py)
- Py_DECREF(type->tp_dict);
- type->tp_dict = new_dict;
+ Py_DECREF(PepType_GetDict(type));
+ PepType_SetDict(type, new_dict);
return true;
}
@@ -184,7 +184,7 @@ static bool addNewDict(PyTypeObject *type, int select_id)
* Add a new dict to the ring and set it as `type->tp_dict`.
* A 'false' return is fatal.
*/
- auto *dict = type->tp_dict;
+ AutoDecRef dict(PepType_GetDict(type));
auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
if (new_dict == nullptr)
@@ -194,7 +194,7 @@ static bool addNewDict(PyTypeObject *type, int select_id)
auto next_dict = nextInCircle(dict);
setNextDict(dict, new_dict);
setNextDict(new_dict, next_dict);
- type->tp_dict = new_dict;
+ PepType_SetDict(type, new_dict);
return true;
}
@@ -204,18 +204,19 @@ static inline bool moveToFeatureSet(PyTypeObject *type, int select_id)
* Rotate the ring to the given `select_id` and return `true`.
* If not found, stay at the current position and return `false`.
*/
- auto *initial_dict = type->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *initial_dict = tpDict.object();
auto *dict = initial_dict;
do {
int current_id = getSelectId(dict);
// This works because small numbers are singleton objects.
if (current_id == select_id) {
- type->tp_dict = dict;
+ PepType_SetDict(type, dict);
return true;
}
dict = nextInCircle(dict);
} while (dict != initial_dict);
- type->tp_dict = initial_dict;
+ PepType_SetDict(type, initial_dict);
return false;
}
@@ -234,8 +235,7 @@ static bool createNewFeatureSet(PyTypeObject *type, int select_id)
Q_UNUSED(ok);
assert(ok);
- AutoDecRef prev_dict(type->tp_dict);
- Py_INCREF(prev_dict); // keep the first ref unchanged
+ AutoDecRef prev_dict(PepType_GetDict(type));
if (!addNewDict(type, select_id))
return false;
int id = select_id;
@@ -245,13 +245,14 @@ static bool createNewFeatureSet(PyTypeObject *type, int select_id)
for (int idx = id; *proc != nullptr; ++proc, idx >>= 1) {
if (idx & 1) {
// clear the tp_dict that will get new content
- PyDict_Clear(type->tp_dict);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyDict_Clear(tpDict);
// let the proc re-fill the tp_dict
if (!(*proc)(type, prev_dict, id))
return false;
// if there is still a step, prepare `prev_dict`
if (idx >> 1) {
- prev_dict.reset(PyDict_Copy(type->tp_dict));
+ prev_dict.reset(PyDict_Copy(tpDict.object()));
if (prev_dict.isNull())
return false;
}
@@ -267,7 +268,8 @@ static inline void SelectFeatureSetSubtype(PyTypeObject *type, int select_id)
* every subclass until no more subclasses or reaching the wanted id.
*/
static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
- if (Py_TYPE(type->tp_dict) == Py_TYPE(pyTypeType_tp_dict)) {
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (Py_TYPE(tpDict.object()) == Py_TYPE(pyTypeType_tp_dict)) {
// On first touch, we initialize the dynamic naming.
// The dict type will be replaced after the first call.
if (!replaceClassDict(type)) {
@@ -322,7 +324,8 @@ static inline void SelectFeatureSet(PyTypeObject *type)
* Shiboken will assign it via a public hook of `basewrapper.cpp`.
*/
static const auto *pyTypeType_tp_dict = PepType_GetDict(&PyType_Type);
- if (Py_TYPE(type->tp_dict) == Py_TYPE(pyTypeType_tp_dict)) {
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (Py_TYPE(tpDict.object()) == Py_TYPE(pyTypeType_tp_dict)) {
// We initialize the dynamic features by using our own dict type.
if (!replaceClassDict(type)) {
Py_FatalError("failed to replace class dict!");
@@ -456,7 +459,8 @@ static PyObject *methodWithNewName(PyTypeObject *type,
static bool feature_01_addLowerNames(PyTypeObject *type, PyObject *prev_dict, int /* id */)
{
PyMethodDef *meth = type->tp_methods;
- PyObject *lower_dict = type->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *lower_dict = tpDict.object();
// PYSIDE-1702: A user-defined class in Python has no internal method list.
// We are not going to change anything.
@@ -632,7 +636,8 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
*/
PyMethodDef *meth = type->tp_methods;
- PyObject *prop_dict = type->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *prop_dict = tpDict.object();
// The empty `tp_dict` gets populated by the previous dict.
if (PyDict_Update(prop_dict, prev_dict) < 0)
@@ -765,7 +770,8 @@ static bool patch_property_impl()
#define SIMILAR_FEATURE(xx) \
static bool feature_##xx##_addDummyNames(PyTypeObject *type, PyObject *prev_dict, int /* id */) \
{ \
- PyObject *dict = type->tp_dict; \
+ AutoDecRef tpDict(PepType_GetDict(type)); \
+ PyObject *dict = tpDict.object(); \
if (PyDict_Update(dict, prev_dict) < 0) \
return false; \
if (PyDict_SetItemString(dict, "fake_feature_" #xx, Py_None) < 0) \
diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp
index 64eb62b76..073e7c2ff 100644
--- a/sources/pyside6/libpyside/pysidesignal.cpp
+++ b/sources/pyside6/libpyside/pysidesignal.cpp
@@ -1100,7 +1100,8 @@ static typename T::value_type join(T t, const char *sep)
static void _addSignalToWrapper(PyTypeObject *wrapperType, const char *signalName, PySideSignal *signal)
{
- auto typeDict = wrapperType->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(wrapperType));
+ auto typeDict = tpDict.object();
PyObject *homonymousMethod;
if ((homonymousMethod = PyDict_GetItemString(typeDict, signalName))) {
Py_INCREF(homonymousMethod);
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
index 7e46cdd02..f746ea714 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
@@ -221,7 +221,8 @@ CppGenerator::OpaqueContainerData
s << "static inline PyTypeObject *" << typeCreationFName << "()\n{\n" << indent
<< "auto *result = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&"
<< specName << "));\nPy_INCREF(Py_True);\n"
- << "PyDict_SetItem(result->tp_dict, "
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(result));\n"
+ << "PyDict_SetItem(tpDict.object(), "
"Shiboken::PyMagicName::opaque_container(), Py_True);\n"
<< "return result;\n" << outdent << "}\n\n";
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
index 66104123f..adeaf6487 100644
--- a/sources/shiboken6/libshiboken/basewrapper.cpp
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -111,7 +111,8 @@ type_set_doc(PyTypeObject *type, PyObject *value, void * /* context */)
if (!check_set_special_type_attr(type, value, "__doc__"))
return -1;
PyType_Modified(type);
- return PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::doc(), value);
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(type));
+ return PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::doc(), value);
}
// PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
index 459efab59..cdb3c311b 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -330,8 +330,10 @@ PyObject *BindingManager::getOverride(const void *cptr,
// The last class in the mro (size - 1) is the base Python object class which should not be tested also.
for (int idx = 1; idx < size - 1; ++idx) {
auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
- if (parent->tp_dict) {
- defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName);
+ AutoDecRef tpDict(PepType_GetDict(parent));
+ auto *parentDict = tpDict.object();
+ if (parentDict) {
+ defaultMethod = PyDict_GetItem(parentDict, pyMethodName);
if (defaultMethod) {
defaultFound = true;
if (function != defaultMethod)
diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp
index 888fbdf5d..348c62120 100644
--- a/sources/shiboken6/libshiboken/pep384impl.cpp
+++ b/sources/shiboken6/libshiboken/pep384impl.cpp
@@ -115,6 +115,8 @@ check_PyTypeObject_valid()
PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset());
long probe_tp_dictoffset = PyLong_AsLong(d);
PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro());
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(check));
+ auto *checkDict = tpDict.object();
if (false
|| strcmp(probe_tp_name, check->tp_name) != 0
|| probe_tp_basicsize != check->tp_basicsize
@@ -131,8 +133,8 @@ check_PyTypeObject_valid()
|| probe_tp_methods != check->tp_methods
|| probe_tp_getset != check->tp_getset
|| probe_tp_base != typetype->tp_base
- || !PyDict_Check(check->tp_dict)
- || !PyDict_GetItemString(check->tp_dict, "dummy")
+ || !PyDict_Check(checkDict)
+ || !PyDict_GetItemString(checkDict, "dummy")
|| probe_tp_descr_get != check->tp_descr_get
|| probe_tp_descr_set != check->tp_descr_set
|| probe_tp_dictoffset != typetype->tp_dictoffset
@@ -1064,6 +1066,12 @@ PyObject *PepType_GetDict(PyTypeObject *type)
#endif // Py_LIMITED_API
}
+int PepType_SetDict(PyTypeObject *type, PyObject *dict)
+{
+ type->tp_dict = dict;
+ return 0;
+}
+
/***************************************************************************
*
* PYSIDE-535: The enum/flag error
diff --git a/sources/shiboken6/libshiboken/pep384impl.h b/sources/shiboken6/libshiboken/pep384impl.h
index 883825f80..0a6e9a1a6 100644
--- a/sources/shiboken6/libshiboken/pep384impl.h
+++ b/sources/shiboken6/libshiboken/pep384impl.h
@@ -548,6 +548,10 @@ extern LIBSHIBOKEN_API int PepRuntime_38_flag;
LIBSHIBOKEN_API PyObject *PepType_GetDict(PyTypeObject *type);
+// This function does not exist as PyType_SetDict. But because tp_dict
+// is no longer considered to be accessible, we treat it as such.
+LIBSHIBOKEN_API int PepType_SetDict(PyTypeObject *type, PyObject *dict);
+
/*****************************************************************************
*
* Module Initialization
diff --git a/sources/shiboken6/libshiboken/sbkcontainer.cpp b/sources/shiboken6/libshiboken/sbkcontainer.cpp
index 13c9f1a29..40fb48527 100644
--- a/sources/shiboken6/libshiboken/sbkcontainer.cpp
+++ b/sources/shiboken6/libshiboken/sbkcontainer.cpp
@@ -8,9 +8,11 @@ namespace Shiboken
{
bool isOpaqueContainer(PyObject *o)
{
+ if (!o)
+ return false;
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(o->ob_type));
return o != nullptr && o != Py_None
- && PyDict_Contains(o->ob_type->tp_dict,
- Shiboken::PyMagicName::opaque_container()) == 1;
+ && PyDict_Contains(tpDict.object(), Shiboken::PyMagicName::opaque_container()) == 1;
}
} // Shiboken
diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp
index ced75f094..d39369979 100644
--- a/sources/shiboken6/libshiboken/sbkenum.cpp
+++ b/sources/shiboken6/libshiboken/sbkenum.cpp
@@ -148,10 +148,11 @@ static PyObject *missing_func(PyObject * /* self */ , PyObject *args)
if (!PyLong_Check(value))
Py_RETURN_NONE;
auto *type = reinterpret_cast<PyTypeObject *>(klass);
- auto *sbk_missing = PyDict_GetItem(type->tp_dict, _sbk_missing);
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto *sbk_missing = PyDict_GetItem(tpDict.object(), _sbk_missing);
if (!sbk_missing) {
sbk_missing = PyDict_New();
- PyDict_SetItem(type->tp_dict, _sbk_missing, sbk_missing);
+ PyDict_SetItem(tpDict.object(), _sbk_missing, sbk_missing);
}
// See if the value is already in the dict.
AutoDecRef val_str(PyObject_CallMethod(value, "__str__", nullptr));
@@ -248,7 +249,8 @@ PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue,
return PyObject_CallFunction(obEnumType, "L", itemValue);
static PyObject *const _member_map_ = String::createStaticString("_member_map_");
- auto *member_map = PyDict_GetItem(enumType->tp_dict, _member_map_);
+ AutoDecRef tpDict(PepType_GetDict(enumType));
+ auto *member_map = PyDict_GetItem(tpDict.object(), _member_map_);
if (!(member_map && PyDict_Check(member_map)))
return nullptr;
auto *result = PyDict_GetItemString(member_map, itemName);
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
index f33e58e9a..0c8f6d3fc 100644
--- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -23,7 +23,8 @@ extern "C"
//
int currentSelectId(PyTypeObject *type)
{
- PyObject *PyId = PyObject_GetAttr(type->tp_dict, PyName::select_id());
+ AutoDecRef tpDict(PepType_GetDict(type));
+ PyObject *PyId = PyObject_GetAttr(tpDict.object(), PyName::select_id());
if (PyId == nullptr) {
PyErr_Clear();
return 0x00;
@@ -235,7 +236,8 @@ static PyObject *lookupUnqualifiedOrOldEnum(PyTypeObject *type, PyObject *name)
* We first need to look into the current opcode of the bytecode to find
* out if we have a call like above or just a type lookup.
*/
- auto *flagType = PyDict_GetItem(type_base->tp_dict, rename);
+ AutoDecRef tpDict(PepType_GetDict(type_base));
+ auto *flagType = PyDict_GetItem(tpDict.object(), rename);
if (currentOpcode_Is_CallMethNoArgs())
return replaceNoArgWithZero(flagType);
Py_INCREF(flagType);
@@ -244,7 +246,8 @@ static PyObject *lookupUnqualifiedOrOldEnum(PyTypeObject *type, PyObject *name)
}
bool useFakeShortcuts = !(Enum::enumOption & Enum::ENOPT_NO_FAKESHORTCUT);
if (useFakeShortcuts) {
- auto *dict = type_base->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type_base));
+ auto *dict = tpDict.object();
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(dict, &pos, &key, &value)) {
@@ -334,12 +337,14 @@ PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void * /* context */)
/*
* This is the override for getting a dict.
*/
- auto dict = type->tp_dict;
+ AutoDecRef tpDict(PepType_GetDict(type));
+ auto dict = tpDict.object();;
if (dict == nullptr)
Py_RETURN_NONE;
if (SelectFeatureSet != nullptr) {
SelectFeatureSet(type);
- dict = type->tp_dict;
+ tpDict.reset(PepType_GetDict(type));
+ dict = tpDict.object();
}
return PyDictProxy_New(dict);
}
diff --git a/sources/shiboken6/libshiboken/sbktypefactory.cpp b/sources/shiboken6/libshiboken/sbktypefactory.cpp
index 559e72263..b4a0fda9c 100644
--- a/sources/shiboken6/libshiboken/sbktypefactory.cpp
+++ b/sources/shiboken6/libshiboken/sbktypefactory.cpp
@@ -130,9 +130,10 @@ PyTypeObject *SbkType_FromSpec_BMDWB(PyType_Spec *spec,
// PyType_Ready too early. (at least in PyPy, which caused pretty long debugging.)
auto *ht = reinterpret_cast<PyHeapTypeObject *>(type);
ht->ht_qualname = qualname;
- if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::qualname(), qualname))
+ AutoDecRef tpDict(PepType_GetDict(type));
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::qualname(), qualname))
return nullptr;
- if (PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::module(), module))
+ if (PyDict_SetItem(tpDict.object(), Shiboken::PyMagicName::module(), module))
return nullptr;
PyType_Ready(type);
#else
@@ -361,7 +362,7 @@ _PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
/// Here is the only change needed: Do not finalize type creation.
// if (PyType_Ready(type) < 0)
// goto fail;
- type->tp_dict = PyDict_New();
+ PepType_SetDict(type, PyDict_New());
/// This is not found in PyPy:
// if (type->tp_dictoffset) {
// res->ht_cached_keys = _PyDict_NewKeysForClass();