diff options
Diffstat (limited to 'libshiboken/basewrapper.cpp')
-rw-r--r-- | libshiboken/basewrapper.cpp | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp index 71abbb6..d82297d 100644 --- a/libshiboken/basewrapper.cpp +++ b/libshiboken/basewrapper.cpp @@ -1105,7 +1105,38 @@ bool isValid(PyObject* pyObj, bool throwPyError) return isValid(reinterpret_cast<SbkObject*>(pyObj), throwPyError); } -PyObject* newObject(SbkObjectType* instanceType, +SbkObject *findColocatedChild(SbkObject* wrapper, + SbkObjectType* instanceType) +{ + // Degenerate case, wrapper is the correct wrapper. + if (reinterpret_cast<const void *>(Py_TYPE(wrapper)) == reinterpret_cast<const void *>(instanceType)) + return wrapper; + + if (!(wrapper->d && wrapper->d->cptr)) + return 0; + + ParentInfo* pInfo = wrapper->d->parentInfo; + if (!pInfo) + return 0; + + ChildrenList& children = pInfo->children; + + ChildrenList::iterator childrenEnd = children.end(); + for (ChildrenList::iterator iChild = children.begin(); iChild != childrenEnd; ++iChild) { + if (!((*iChild)->d && (*iChild)->d->cptr)) + continue; + if ((*iChild)->d->cptr[0] == wrapper->d->cptr[0]) { + if (reinterpret_cast<const void *>(Py_TYPE(*iChild)) == reinterpret_cast<const void *>(instanceType)) + return const_cast<SbkObject *>((*iChild)); + else + return findColocatedChild(const_cast<SbkObject *>(*iChild), instanceType); + } + } + return 0; +} + + +PyObject *newObject(SbkObjectType* instanceType, void* cptr, bool hasOwnership, bool isExactType, @@ -1123,11 +1154,45 @@ PyObject* newObject(SbkObjectType* instanceType, instanceType = BindingManager::instance().resolveType(&cptr, instanceType); } - SbkObject* self = reinterpret_cast<SbkObject*>(SbkObjectTpNew(reinterpret_cast<PyTypeObject*>(instanceType), 0, 0)); - self->d->cptr[0] = cptr; - self->d->hasOwnership = hasOwnership; - self->d->validCppObject = 1; - BindingManager::instance().registerWrapper(self, cptr); + bool shouldCreate = true; + bool shouldRegister = true; + SbkObject* self = 0; + + // Some logic to ensure that colocated child field does not overwrite the parent + if (BindingManager::instance().hasWrapper(cptr)) { + SbkObject* existingWrapper = BindingManager::instance().retrieveWrapper(cptr); + + self = findColocatedChild(existingWrapper, instanceType); + if (self) { + // Wrapper already registered for cptr. + // This should not ideally happen, binding code should know when a wrapper + // already exists and retrieve it instead. + shouldRegister = shouldCreate = false; + } else if (hasOwnership && + (!(Shiboken::Object::hasCppWrapper(existingWrapper) || + Shiboken::Object::hasOwnership(existingWrapper)))) { + // Old wrapper is likely junk, since we have ownership and it doesn't. + BindingManager::instance().releaseWrapper(existingWrapper); + } else { + // Old wrapper may be junk caused by some bug in identifying object deletion + // but it may not be junk when a colocated field is accessed for an + // object which was not created by python (returned from c++ factory function). + // Hence we cannot release the wrapper confidently so we do not register. + shouldRegister = false; + } + } + + if (shouldCreate) { + self = reinterpret_cast<SbkObject*>(SbkObjectTpNew(reinterpret_cast<PyTypeObject*>(instanceType), 0, 0)); + self->d->cptr[0] = cptr; + self->d->hasOwnership = hasOwnership; + self->d->validCppObject = 1; + if (shouldRegister) { + BindingManager::instance().registerWrapper(self, cptr); + } + } else { + Py_IncRef(reinterpret_cast<PyObject*>(self)); + } return reinterpret_cast<PyObject*>(self); } |