From 5135a35677e25c473db0e8a463f97c15359c9e34 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 7 Feb 2007 12:50:48 +0000 Subject: [PATCH] Fix memory leak where Struct, _LongBase, _StrBase, String leaked their __dict__ on deallocation. * Use a fixed-size struct for String (unicode objects are in fact fixed-size) and store its variant_level that way. * Don't store Struct, _LongBase, _StrBase variant_level and Struct signature in a __dict__, but instead have a global dict mapping object IDs to variant levels, and a global dict mapping Struct IDs to signatures. This is a bit strange, but easier than correctly freeing the __dict__ (which is stored at the end of a variable-length struct, so somewhat hard to get at). * With this change, allocating objects in a loop no longer leaks memory, and neither does the test case supplied by Luka Renko. --- _dbus_bindings/abstract.c | 194 ++++++++++++++++++++++++++++++++-------- _dbus_bindings/containers.c | 132 +++++++++++++++++++++------ _dbus_bindings/message-append.c | 6 +- _dbus_bindings/string.c | 75 +++++++--------- _dbus_bindings/types-internal.h | 10 +++ 5 files changed, 309 insertions(+), 108 deletions(-) diff --git a/_dbus_bindings/abstract.c b/_dbus_bindings/abstract.c index 57a4e04..f33996b 100644 --- a/_dbus_bindings/abstract.c +++ b/_dbus_bindings/abstract.c @@ -28,6 +28,123 @@ #include "dbus_bindings-internal.h" #include "types-internal.h" +/* Dict indexed by object IDs, whose values are nonzero variant levels + * for immutable variable-sized D-Bus data types (_LongBase, _StrBase, Struct). + * + * This is a strange way to store them, but adding a __dict__ to the offending + * objects seems even more error-prone, given that their sizes are variable! + */ +PyObject *_dbus_py_variant_levels = NULL; + +long +dbus_py_variant_level_get(PyObject *obj) +{ + PyObject *vl_obj; + PyObject *key = PyLong_FromVoidPtr(obj); + + if (!key) { + return 0; + } + + vl_obj = PyDict_GetItem(_dbus_py_variant_levels, key); + Py_DECREF(key); + + if (!vl_obj) + return 0; + return PyInt_AsLong(vl_obj); +} + +dbus_bool_t +dbus_py_variant_level_set(PyObject *obj, long variant_level) +{ + /* key is the object's ID (= pointer) to avoid referencing it */ + PyObject *key = PyLong_FromVoidPtr(obj); + + if (!key) { + return FALSE; + } + + if (variant_level <= 0) { + if (PyDict_GetItem (_dbus_py_variant_levels, key)) { + if (PyDict_DelItem (_dbus_py_variant_levels, key) < 0) { + Py_DECREF(key); + return FALSE; + } + } + } + else { + PyObject *vl_obj = PyInt_FromLong(variant_level); + if (!vl_obj) { + Py_DECREF(key); + return FALSE; + } + if (PyDict_SetItem (_dbus_py_variant_levels, key, vl_obj) < 0) { + Py_DECREF(key); + return FALSE; + } + } + Py_DECREF(key); + return TRUE; +} + +PyObject * +dbus_py_variant_level_getattro(PyObject *obj, PyObject *name) +{ + PyObject *key, *value; + + if (PyString_Check(name)) { + Py_INCREF(name); + } + else if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (!name) { + return NULL; + } + } + else { + PyErr_SetString(PyExc_TypeError, "attribute name must be string"); + return NULL; + } + + if (strcmp(PyString_AS_STRING(name), "variant_level")) { + value = PyObject_GenericGetAttr(obj, name); + Py_DECREF(name); + return value; + } + + Py_DECREF(name); + + key = PyLong_FromVoidPtr(obj); + + if (!key) { + return NULL; + } + + value = PyDict_GetItem(_dbus_py_variant_levels, key); + Py_DECREF(key); + + if (!value) + return PyInt_FromLong(0); + Py_INCREF(value); + return value; +} + +/* To be invoked by destructors. Clear the variant level without touching the + * exception state */ +void +dbus_py_variant_level_clear(PyObject *self) +{ + PyObject *et, *ev, *etb; + + /* avoid clobbering any pending exception */ + PyErr_Fetch(&et, &ev, &etb); + if (!dbus_py_variant_level_set(self, 0)) { + /* should never happen */ + PyErr_WriteUnraisable(self); + } + PyErr_Restore(et, ev, etb); +} + /* Support code for int subclasses. ================================== */ PyDoc_STRVAR(DBusPythonInt_tp_doc,\ @@ -259,7 +376,7 @@ static PyObject * DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) { PyObject *self; - PyObject *variantness = NULL; + long variantness = 0; static char *argnames[] = {"variant_level", NULL}; if (PyTuple_Size(args) > 1) { @@ -268,13 +385,9 @@ DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) return NULL; } if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|O!:__new__", argnames, - &PyInt_Type, &variantness)) return NULL; - if (!variantness) { - variantness = PyInt_FromLong(0); - if (!variantness) return NULL; - } - if (PyInt_AS_LONG(variantness) < 0) { + "|l:__new__", argnames, + &variantness)) return NULL; + if (variantness < 0) { PyErr_SetString(PyExc_ValueError, "variant_level must be non-negative"); return NULL; @@ -282,7 +395,10 @@ DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) self = (PyString_Type.tp_new)(cls, args, NULL); if (self) { - PyObject_GenericSetAttr(self, dbus_py_variant_level_const, variantness); + if (!dbus_py_variant_level_set(self, variantness)) { + Py_DECREF(self); + return NULL; + } } return self; } @@ -318,13 +434,20 @@ DBusPythonString_tp_repr(PyObject *self) return my_repr; } +static void +DBusPyStrBase_tp_dealloc(PyObject *self) +{ + dbus_py_variant_level_clear(self); + (PyString_Type.tp_dealloc)(self); +} + PyTypeObject DBusPyStrBase_Type = { PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) 0, "_dbus_bindings._StrBase", - INT_MAX, /* placeholder */ + 0, 0, - 0, /* tp_dealloc */ + DBusPyStrBase_tp_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -336,7 +459,7 @@ PyTypeObject DBusPyStrBase_Type = { 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ + dbus_py_variant_level_getattro, /* tp_getattro */ dbus_py_immutable_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ @@ -354,7 +477,7 @@ PyTypeObject DBusPyStrBase_Type = { 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - -sizeof(void *), /* tp_dictoffset */ + 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ DBusPythonString_tp_new, /* tp_new */ @@ -371,7 +494,7 @@ static PyObject * DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) { PyObject *self; - PyObject *variantness = NULL; + long variantness = 0; static char *argnames[] = {"variant_level", NULL}; if (PyTuple_Size(args) > 1) { @@ -380,13 +503,9 @@ DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) return NULL; } if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|O!:__new__", argnames, - &PyInt_Type, &variantness)) return NULL; - if (!variantness) { - variantness = PyInt_FromLong(0); - if (!variantness) return NULL; - } - if (PyInt_AS_LONG(variantness) < 0) { + "|l:__new__", argnames, + &variantness)) return NULL; + if (variantness < 0) { PyErr_SetString(PyExc_ValueError, "variant_level must be non-negative"); return NULL; @@ -394,7 +513,10 @@ DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) self = (PyLong_Type.tp_new)(cls, args, NULL); if (self) { - PyObject_GenericSetAttr(self, dbus_py_variant_level_const, variantness); + if (!dbus_py_variant_level_set(self, variantness)) { + Py_DECREF(self); + return NULL; + } } return self; } @@ -430,13 +552,20 @@ DBusPythonLong_tp_repr(PyObject *self) return my_repr; } +static void +DBusPyLongBase_tp_dealloc(PyObject *self) +{ + dbus_py_variant_level_clear(self); + (PyLong_Type.tp_dealloc)(self); +} + PyTypeObject DBusPyLongBase_Type = { PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) 0, "_dbus_bindings._LongBase", - INT_MAX, /* placeholder */ + 0, 0, - 0, /* tp_dealloc */ + DBusPyLongBase_tp_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -448,7 +577,7 @@ PyTypeObject DBusPyLongBase_Type = { 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ + dbus_py_variant_level_getattro, /* tp_getattro */ dbus_py_immutable_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ @@ -466,7 +595,7 @@ PyTypeObject DBusPyLongBase_Type = { 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - -sizeof(PyObject *), /* tp_dictoffset */ + 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ DBusPythonLong_tp_new, /* tp_new */ @@ -479,6 +608,9 @@ PyObject *dbus_py__dbus_object_path__const = NULL; dbus_bool_t dbus_py_init_abstract(void) { + _dbus_py_variant_levels = PyDict_New(); + if (!_dbus_py_variant_levels) return 0; + dbus_py__dbus_object_path__const = PyString_InternFromString("__dbus_object_path__"); if (!dbus_py__dbus_object_path__const) return 0; @@ -498,20 +630,10 @@ dbus_py_init_abstract(void) if (PyType_Ready(&DBusPyFloatBase_Type) < 0) return 0; DBusPyFloatBase_Type.tp_print = NULL; - /* Add a pointer for the instance dict, aligning to sizeof(PyObject *) - * to make sure the offset of -sizeof(PyObject *) is right. */ - DBusPyLongBase_Type.tp_basicsize = PyLong_Type.tp_basicsize - + 2*sizeof(PyObject *) - 1; - DBusPyLongBase_Type.tp_basicsize /= sizeof(PyObject *); - DBusPyLongBase_Type.tp_basicsize *= sizeof(PyObject *); DBusPyLongBase_Type.tp_base = &PyLong_Type; if (PyType_Ready(&DBusPyLongBase_Type) < 0) return 0; DBusPyLongBase_Type.tp_print = NULL; - DBusPyStrBase_Type.tp_basicsize = PyString_Type.tp_basicsize - + 2*sizeof(PyObject *) - 1; - DBusPyStrBase_Type.tp_basicsize /= sizeof(PyObject *); - DBusPyStrBase_Type.tp_basicsize *= sizeof(PyObject *); DBusPyStrBase_Type.tp_base = &PyString_Type; if (PyType_Ready(&DBusPyStrBase_Type) < 0) return 0; DBusPyStrBase_Type.tp_print = NULL; diff --git a/_dbus_bindings/containers.c b/_dbus_bindings/containers.c index 4dc9046..ee38032 100644 --- a/_dbus_bindings/containers.c +++ b/_dbus_bindings/containers.c @@ -474,6 +474,8 @@ PyTypeObject DBusPyDict_Type = { /* Struct =========================================================== */ +static PyObject *struct_signatures; + PyDoc_STRVAR(Struct_tp_doc, "An structure containing items of possibly distinct types.\n" "\n" @@ -505,20 +507,21 @@ static PyObject * Struct_tp_repr(PyObject *self) { PyObject *parent_repr = (PyTuple_Type.tp_repr)((PyObject *)self); - PyObject *sig = NULL; + PyObject *sig; PyObject *sig_repr = NULL; - PyObject *vl_obj = NULL; + PyObject *key; long variant_level; PyObject *my_repr = NULL; if (!parent_repr) goto finally; - sig = PyObject_GetAttr(self, dbus_py_signature_const); - if (!sig) goto finally; + key = PyLong_FromVoidPtr(self); + if (!key) goto finally; + sig = PyDict_GetItem(struct_signatures, key); + Py_DECREF(key); + if (!sig) sig = Py_None; sig_repr = PyObject_Repr(sig); if (!sig_repr) goto finally; - vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const); - if (!vl_obj) goto finally; - variant_level = PyInt_AsLong(vl_obj); + variant_level = dbus_py_variant_level_get(self); if (variant_level > 0) { my_repr = PyString_FromFormat("%s(%s, signature=%s, " "variant_level=%ld)", @@ -536,9 +539,7 @@ Struct_tp_repr(PyObject *self) finally: Py_XDECREF(parent_repr); - Py_XDECREF(sig); Py_XDECREF(sig_repr); - Py_XDECREF(vl_obj); return my_repr; } @@ -546,8 +547,8 @@ static PyObject * Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) { PyObject *signature = NULL; - PyObject *variantness = NULL; - PyObject *self; + long variantness = 0; + PyObject *self, *key; static char *argnames[] = {"signature", "variant_level", NULL}; if (PyTuple_Size(args) != 1) { @@ -556,13 +557,14 @@ Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) return NULL; } if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|OO!:__new__", argnames, - &signature, &PyInt_Type, - &variantness)) { + "|Ol:__new__", argnames, + &signature, &variantness)) { return NULL; } - if (!variantness) { - variantness = PyInt_FromLong(0); + if (variantness < 0) { + PyErr_SetString(PyExc_ValueError, + "variant_level must be non-negative"); + return NULL; } self = (PyTuple_Type.tp_new)(cls, args, NULL); @@ -574,7 +576,7 @@ Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) return NULL; } - if (PyObject_GenericSetAttr(self, dbus_py_variant_level_const, variantness) < 0) { + if (!dbus_py_variant_level_set(self, variantness)) { Py_DECREF(self); return NULL; } @@ -595,22 +597,101 @@ Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs) } } - if (PyObject_GenericSetAttr(self, dbus_py_signature_const, signature) < 0) { + key = PyLong_FromVoidPtr(self); + if (!key) { + Py_DECREF(self); + Py_DECREF(signature); + return NULL; + } + if (PyDict_SetItem(struct_signatures, key, signature) < 0) { + Py_DECREF(key); Py_DECREF(self); Py_DECREF(signature); return NULL; } + + Py_DECREF(key); Py_DECREF(signature); return self; } +static void +Struct_tp_dealloc(PyObject *self) +{ + PyObject *et, *ev, *etb, *key; + + dbus_py_variant_level_clear(self); + PyErr_Fetch(&et, &ev, &etb); + + key = PyLong_FromVoidPtr(self); + if (key) { + if (PyDict_GetItem(struct_signatures, key)) { + if (PyDict_DelItem(struct_signatures, key) < 0) { + /* should never happen */ + PyErr_WriteUnraisable(self); + } + } + Py_DECREF(key); + } + else { + /* not enough memory to free all the memory... leak the signature, + * there's not much else we could do here */ + PyErr_WriteUnraisable(self); + } + + PyErr_Restore(et, ev, etb); + (PyTuple_Type.tp_dealloc)(self); +} + +PyObject * +Struct_tp_getattro(PyObject *obj, PyObject *name) +{ + PyObject *key, *value; + + if (PyString_Check(name)) { + Py_INCREF(name); + } + else if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (!name) { + return NULL; + } + } + else { + PyErr_SetString(PyExc_TypeError, "attribute name must be string"); + return NULL; + } + + if (strcmp(PyString_AS_STRING(name), "signature")) { + value = dbus_py_variant_level_getattro(obj, name); + Py_DECREF(name); + return value; + } + + Py_DECREF(name); + + key = PyLong_FromVoidPtr(obj); + + if (!key) { + return NULL; + } + + value = PyDict_GetItem(struct_signatures, key); + Py_DECREF(key); + + if (!value) + value = Py_None; + Py_INCREF(value); + return value; +} + PyTypeObject DBusPyStruct_Type = { PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) 0, "dbus.Struct", - INT_MAX, /* placeholder */ 0, - 0, /* tp_dealloc */ + 0, + Struct_tp_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -622,7 +703,7 @@ PyTypeObject DBusPyStruct_Type = { 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ + Struct_tp_getattro, /* tp_getattro */ dbus_py_immutable_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ @@ -640,7 +721,7 @@ PyTypeObject DBusPyStruct_Type = { 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - -sizeof(PyObject *), /* tp_dictoffset */ + 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ Struct_tp_new, /* tp_new */ @@ -649,6 +730,9 @@ PyTypeObject DBusPyStruct_Type = { dbus_bool_t dbus_py_init_container_types(void) { + struct_signatures = PyDict_New(); + if (!struct_signatures) return 0; + DBusPyArray_Type.tp_base = &PyList_Type; if (PyType_Ready(&DBusPyArray_Type) < 0) return 0; DBusPyArray_Type.tp_print = NULL; @@ -657,10 +741,6 @@ dbus_py_init_container_types(void) if (PyType_Ready(&DBusPyDict_Type) < 0) return 0; DBusPyDict_Type.tp_print = NULL; - DBusPyStruct_Type.tp_basicsize = PyTuple_Type.tp_basicsize - + 2*sizeof(PyObject *) - 1; - DBusPyStruct_Type.tp_basicsize /= sizeof(PyObject *); - DBusPyStruct_Type.tp_basicsize *= sizeof(PyObject *); DBusPyStruct_Type.tp_base = &PyTuple_Type; if (PyType_Ready(&DBusPyStruct_Type) < 0) return 0; DBusPyStruct_Type.tp_print = NULL; diff --git a/_dbus_bindings/message-append.c b/_dbus_bindings/message-append.c index d4a56b0..b2a4afd 100644 --- a/_dbus_bindings/message-append.c +++ b/_dbus_bindings/message-append.c @@ -43,11 +43,13 @@ get_variant_level(PyObject *obj) else if (DBusPyDict_Check(obj)) { return ((DBusPyDict *)obj)->variant_level; } + else if (DBusPyString_Check(obj)) { + return ((DBusPyString *)obj)->variant_level; + } else if (DBusPyLongBase_Check(obj) || DBusPyStrBase_Check(obj) || - DBusPyString_Check(obj) || DBusPyStruct_Check(obj)) { - return PyInt_AsLong(PyObject_GetAttr(obj, dbus_py_variant_level_const)); + return dbus_py_variant_level_get(obj); } else { return 0; diff --git a/_dbus_bindings/string.c b/_dbus_bindings/string.c index 096635c..56dfae4 100644 --- a/_dbus_bindings/string.c +++ b/_dbus_bindings/string.c @@ -21,6 +21,7 @@ */ #include "types-internal.h" +#include /* UTF-8 string representation ====================================== */ @@ -226,11 +227,19 @@ PyDoc_STRVAR(String_tp_doc, " String or UTF8String with variant_level==2.\n" ); +static PyMemberDef String_tp_members[] = { + {"variant_level", T_LONG, offsetof(DBusPyString, variant_level), + READONLY, + "The number of nested variants wrapping the real data. " + "0 if not in a variant"}, + {NULL}, +}; + static PyObject * String_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) { PyObject *self; - PyObject *variantness = NULL; + long variantness = 0; static char *argnames[] = {"variant_level", NULL}; if (PyTuple_Size(args) > 1) { @@ -239,32 +248,17 @@ String_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs) return NULL; } if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs, - "|O!:__new__", argnames, - &PyInt_Type, &variantness)) return NULL; - if (variantness) { - if (PyInt_AS_LONG(variantness) < 0) { - PyErr_SetString(PyExc_ValueError, - "variant_level must be non-negative"); - return NULL; - } - /* own a reference */ - Py_INCREF(variantness); - } - else { - variantness = PyInt_FromLong(0); - if (!variantness) return NULL; + "|l:__new__", argnames, + &variantness)) return NULL; + if (variantness < 0) { + PyErr_SetString(PyExc_ValueError, + "variant_level must be non-negative"); + return NULL; } - self = (PyUnicode_Type.tp_new)(cls, args, NULL); if (self) { - if (PyObject_GenericSetAttr(self, dbus_py_variant_level_const, - variantness) < 0) { - Py_DECREF(variantness); - Py_DECREF(self); - return NULL; - } + ((DBusPyString *)self)->variant_level = variantness; } - Py_DECREF(variantness); return self; } @@ -272,23 +266,16 @@ static PyObject * String_tp_repr(PyObject *self) { PyObject *parent_repr = (PyUnicode_Type.tp_repr)(self); - PyObject *vl_obj; PyObject *my_repr; - long variant_level; - if (!parent_repr) return NULL; - vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const); - if (!vl_obj) { - Py_DECREF(parent_repr); + if (!parent_repr) { return NULL; } - variant_level = PyInt_AsLong(vl_obj); - Py_DECREF(vl_obj); - if (variant_level > 0) { + if (((DBusPyString *)self)->variant_level > 0) { my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)", self->ob_type->tp_name, PyString_AS_STRING(parent_repr), - variant_level); + ((DBusPyString *)self)->variant_level); } else { my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name, @@ -303,7 +290,7 @@ PyTypeObject DBusPyString_Type = { PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) 0, "dbus.String", - INT_MAX, /* placeholder */ + sizeof(DBusPyString), 0, 0, /* tp_dealloc */ 0, /* tp_print */ @@ -329,13 +316,13 @@ PyTypeObject DBusPyString_Type = { 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ - 0, /* tp_members */ + String_tp_members, /* tp_members */ 0, /* tp_getset */ DEFERRED_ADDRESS(&PyUnicode_Type), /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - -sizeof(void *), /* tp_dictoffset */ + 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ String_tp_new, /* tp_new */ @@ -344,18 +331,18 @@ PyTypeObject DBusPyString_Type = { dbus_bool_t dbus_py_init_string_types(void) { - DBusPyString_Type.tp_basicsize = PyUnicode_Type.tp_basicsize - + 2*sizeof(PyObject *) - 1; - DBusPyString_Type.tp_basicsize /= sizeof(PyObject *); - DBusPyString_Type.tp_basicsize *= sizeof(PyObject *); + /* don't need to do strange contortions for unicode, since it's not a + * "variable-size" object (it has a pointer to its data instead) + */ + if (PyUnicode_Type.tp_itemsize != 0) { + fprintf(stderr, "dbus-python is not compatible with this version of " + "Python (unicode objects are assumed to be fixed-size)"); + return 0; + } DBusPyString_Type.tp_base = &PyUnicode_Type; if (PyType_Ready(&DBusPyString_Type) < 0) return 0; DBusPyString_Type.tp_print = NULL; - DBusPyUTF8String_Type.tp_basicsize = PyUnicode_Type.tp_basicsize - + 2*sizeof(PyObject *) - 1; - DBusPyUTF8String_Type.tp_basicsize /= sizeof(PyObject *); - DBusPyUTF8String_Type.tp_basicsize *= sizeof(PyObject *); DBusPyUTF8String_Type.tp_base = &DBusPyStrBase_Type; if (PyType_Ready(&DBusPyUTF8String_Type) < 0) return 0; DBusPyUTF8String_Type.tp_print = NULL; diff --git a/_dbus_bindings/types-internal.h b/_dbus_bindings/types-internal.h index f208421..3d7d866 100644 --- a/_dbus_bindings/types-internal.h +++ b/_dbus_bindings/types-internal.h @@ -47,6 +47,11 @@ typedef struct { long variant_level; } DBusPyFloatBase; +typedef struct { + PyUnicodeObject unicode; + long variant_level; +} DBusPyString; + extern PyTypeObject DBusPyStrBase_Type; DEFINE_CHECK(DBusPyStrBase) @@ -79,4 +84,9 @@ typedef struct { long variant_level; } DBusPyDict; +PyObject *dbus_py_variant_level_getattro(PyObject *obj, PyObject *name); +dbus_bool_t dbus_py_variant_level_set(PyObject *obj, long variant_level); +void dbus_py_variant_level_clear(PyObject *obj); +long dbus_py_variant_level_get(PyObject *obj); + #endif -- 2.11.4.GIT