custodian=xxx memory problems

Bug #461349 reported by Gustavo Carneiro
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
PyBindGen
Fix Released
Medium
Unassigned

Bug Description

--- example.hh ---
#include <iostream>

class A {
public:
  A(int val = 0): mVal(val) { std::cout << "A constructor." << std::endl; }
  virtual ~A() {}
  int val() const { return mVal; }
  void val(int x) { mVal = x; }
private:
  int mVal;
};

class B {
public:
  B(): mAptr(new A) { std::cout << "B constructor with " << mAptr << std::endl; }
  virtual ~B() {}
  A* Aptr() { return mAptr; }
private:
  A* mAptr;
};

--- example-gen.py ---
from pybindgen import *
import sys

mod = Module("example")
mod.add_include('"example.hh"')

a = mod.add_class("A", allow_subclassing=True)
a.add_constructor([param("int", "val", default_value="0")])
a.add_instance_attribute("val", "int", getter="val", setter="val")

b = mod.add_class("B", allow_subclassing=True)
b.add_constructor([])
#b.add_method("Aptr", retval("A*", caller_owns_return=False), [])
#b.add_method("Aptr", retval("A*", caller_owns_return=True), [])
b.add_method("Aptr", retval("A*", custodian=0), [])

f = open("example.C", "w")
mod.generate(FileCodeSink(f))
f.close()

--- test.py ---

import example
b = example.B()
a = b.Aptr()
print "Before changing: ", a.val, b.Aptr().val
a.val = 10
print "After changing: ", a.val, b.Aptr().val

--- valgrind ---

==10091== Invalid read of size 8
==10091== at 0x6058AFB: PyA__tp_clear(PyA*) (example.C:138)
==10091== by 0x6058B75: _wrap_PyA__tp_dealloc(PyA*) (example.C:154)
==10091== by 0x43DC71: list_dealloc (listobject.c:306)
==10091== by 0x44D832: dict_dealloc (dictobject.c:911)
==10091== by 0x6058F43: PyB__tp_clear(PyB*) (example.C:294)
==10091== by 0x6058FE1: _wrap_PyB__tp_dealloc(PyB*) (example.C:313)
==10091== by 0x44C096: insertdict (dictobject.c:459)
==10091== by 0x44E656: PyDict_SetItem (dictobject.c:701)
==10091== by 0x45010D: _PyModule_Clear (moduleobject.c:138)
==10091== by 0x4B53A9: PyImport_Cleanup (import.c:439)
==10091== by 0x4C2C34: Py_Finalize (pythonrun.c:434)
==10091== by 0x4185C1: Py_Main (main.c:625)
==10091== Address 0x602a660 is 0 bytes inside a block of size 16 free'd
==10091== at 0x4C24A7A: operator delete(void*) (vg_replace_malloc.c:346)
==10091== by 0x605933A: A::~A() (example.hh:8)
==10091== by 0x6058B0D: PyA__tp_clear(PyA*) (example.C:138)
==10091== by 0x6058B75: _wrap_PyA__tp_dealloc(PyA*) (example.C:154)
==10091== by 0x43DC71: list_dealloc (listobject.c:306)
==10091== by 0x44D832: dict_dealloc (dictobject.c:911)
==10091== by 0x6058F43: PyB__tp_clear(PyB*) (example.C:294)
==10091== by 0x6058FE1: _wrap_PyB__tp_dealloc(PyB*) (example.C:313)
==10091== by 0x44C096: insertdict (dictobject.c:459)
==10091== by 0x44E656: PyDict_SetItem (dictobject.c:701)
==10091== by 0x45010D: _PyModule_Clear (moduleobject.c:138)
==10091== by 0x4B53A9: PyImport_Cleanup (import.c:439)

Related branches

Gustavo Carneiro (gjc)
Changed in pybindgen:
status: New → Confirmed
importance: Undecided → Medium
Revision history for this message
Gustavo Carneiro (gjc) wrote :

The test program calls b.Aptr() multiple times, which creates multiple wrappers for class A. At the end of the simulation, each distinct wrapper will try to deallocate the same A instance, causing the double-free.

We need to add a option to create a wrapper which knows the C++ instance is shared and doesn't try to free it. Unfortunately that means adding bytes to the python wrapper structure, but that's life.

Revision history for this message
Gustavo Carneiro (gjc) wrote :

Workaround:

pybindgen.settings.wrapper_registry = pybindgen.settings.StdMapWrapperRegistry

Revision history for this message
Gustavo Carneiro (gjc) wrote :

All fixed in rev. 706.

Changed in pybindgen:
status: Confirmed → Fix Committed
Gustavo Carneiro (gjc)
Changed in pybindgen:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Related questions

Remote bug watches

Bug watches keep track of this bug in other bug trackers.