Multiple memory leak in ALL versions of python-apt
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
python-apt (Ubuntu) |
Fix Released
|
Undecided
|
Michael Vogt |
Bug Description
Binary package hint: python-apt
This bug report references code from python/acquire.cc and python/generic.h. I think it applies to *all* versions of python-apt.
As far as I can tell, every single use of the CppPyObject<T> template with a pointer type for the template parameter T results in a memory leak. To give a concrete example, consider the use of the template in python/acquire.cc:
pkgAcqFile *af = new pkgAcqFile(/* ... */);
CppPyObject
AcqFileObj-
The function registered to deallocate the CppPyObject<
template <class T>
void CppDealloc(PyObject *Obj)
{
}
Notice that it calls the destructor for the contained object. That works when T is a non-pointer type. However, when T is a pointer type, the deconstructor being called is *that of the pointer, not what it points to*. I.e. the destructor call resembles this:
typedef char* T;
T a = new char;
a.~T();
Which of course doesn't really make sense. Calling a.~T() doesn't free the memory pointed to by a. So, when CppDealloc<>() is called with a pointer type, you probably want this:
template <class T>
void CppDealloc(PyObject *Obj)
{
delete GetCpp<T>(Obj)
}
I see several ways to fix this:
1) don't use pointers with CppPyObject<>
2) add a template specialization like CppPyObject<T*> that uses delete instead of calling the destructor directly
3) use smart pointers (std::auto_ptr, or better, boost::shared_ptr) instead of naked pointers
The second option would be easy to implement, but what if you wanted a CppPyObject to contain a pointer without deleting it? The first option is too restrictive. Probably, the third option makes the most sense.
Related branches
Changed in python-apt (Ubuntu): | |
assignee: | nobody → Ubuntu Foundations Team (ubuntu-foundations) |
Changed in python-apt (Ubuntu): | |
assignee: | Ubuntu Foundations Team (ubuntu-foundations) → Michael Vogt (mvo) |
> 2) add a template specialization like CppPyObject<T*> that uses delete instead of calling the destructor directly Ptr().
The problem here is that AFAIK there is no way to define such template specializations for functions. We could still introduce new functions CppDeallocPtr() CppOwnedDealloc
> 3) use smart pointers (std::auto_ptr, or better, boost::shared_ptr) instead of naked pointers
If python-apt were to use smart pointers, this could be a problem for applications wanting to provide their objects in python-apt using the planned C++ API of the upcoming python-apt 0.8. Furthemore it does not make sense to have two reference counters for basically one 'thing' (the CppPyObject itself and the pointer to the C++ object).
> The second option would be easy to implement, but what if you wanted a CppPyObject to contain a pointer without > deleting it? The first option is too restrictive. Probably, the third option makes the most sense.
The third option makes no sense because we would force all programs wanting to export their objects to python to use smart pointers. The second option makes most sense here, but we should introduce a new member 'ShouldDealloc' or similar which can be set in CppPyObject_ NEW()/CppOwnedP yObject_ NEW() and prevents the deallocation. This way, providing a C++ API still works and the program is still responsible for deleting the object, instead of some class somewhere.
I have committed the attached patch to the jak branch and it will be part of the 0.7.92 release.