Skip to content

Commit 3c5df28

Browse files
committed
Bug fix for NULL pointers with return_internal_reference<>.
[SVN r14952]
1 parent 49e071d commit 3c5df28

File tree

4 files changed

+54
-26
lines changed

4 files changed

+54
-26
lines changed

doc/v2/with_custodian_and_ward.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ <h2><a name="introduction">Introduction</a></h2>
6666
the custodian as long as the <i>custodian</i> object supports <a
6767
href="http://www.python.org/doc/current/lib/module-weakref.html">weak
6868
references</a> (Boost.Python extension classes all support weak
69-
references). The two class templates
69+
references). If the <i>custodian</i> object does not support weak
70+
references and is not <code>None</code>, an appropriate exception
71+
will be thrown. The two class templates
7072
<code>with_custodian_and_ward</code> and
7173
<code>with_custodian_and_ward_postcall</code> differ in the point
72-
at which they take effect.
74+
at which they take effect.
7375

7476
<p>In order to reduce the chance of inadvertently
7577
creating dangling pointers, the default is to do lifetime binding

src/object/life_support.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// to its suitability for any purpose.
66
#include <boost/python/object/life_support.hpp>
77
#include <boost/python/detail/none.hpp>
8+
#include <boost/python/refcount.hpp>
89

910
namespace boost { namespace python { namespace objects {
1011

@@ -80,9 +81,17 @@ PyTypeObject life_support_type = {
8081

8182
PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient)
8283
{
84+
if (nurse == Py_None)
85+
return incref(nurse);
86+
87+
if ((life_support_type.tp_flags & Py_TPFLAGS_READY) == 0)
88+
PyType_Ready(&life_support_type);
89+
8390
life_support* system = PyObject_New(life_support, &life_support_type);
8491
if (!system)
8592
return 0;
93+
94+
system->patient = 0;
8695

8796
// We're going to leak this reference, but don't worry; the
8897
// life_support system decrements it when the nurse dies.

test/test_pointer_adoption.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ struct inner
2929
std::string s;
3030
};
3131

32-
struct A
32+
struct Base
33+
{
34+
virtual ~Base() {}
35+
};
36+
37+
struct A : Base
3338
{
3439
A(std::string const& s)
3540
: x(s)
@@ -76,40 +81,47 @@ A* create(std::string const& s)
7681
return new A(s);
7782
}
7883

84+
A* as_A(Base* b)
85+
{
86+
return dynamic_cast<A*>(b);
87+
}
88+
7989
BOOST_PYTHON_MODULE_INIT(test_pointer_adoption_ext)
8090
{
81-
boost::python::module("test_pointer_adoption_ext")
82-
.def("num_a_instances", num_a_instances)
91+
boost::python::module m("test_pointer_adoption_ext");
92+
m.def("num_a_instances", num_a_instances)
8393

8494
// Specify the manage_new_object return policy to take
8595
// ownership of create's result
8696
.def("create", create, return_value_policy<manage_new_object>())
87-
88-
.add(
89-
90-
class_<A>(no_init)
91-
.def("content", &A::content)
92-
.def("get_inner", &A::get_inner, return_internal_reference<>())
93-
)
9497

98+
.def("as_A", as_A, return_internal_reference<>())
9599
.add(
96-
class_<inner>(no_init)
97-
.def("change", &inner::change)
98-
)
100+
101+
class_<Base>("Base")
102+
);
99103

100-
.add(
101-
class_<B>("B")
102-
.def_init(args<A*>(), with_custodian_and_ward_postcall<1,2>())
103-
104-
.def("adopt", &B::adopt
105-
// Adopt returns a pointer referring to a subobject of its 2nd argument (1st being "self")
106-
, return_internal_reference<2
107-
// Meanwhile, self holds a reference to the 2nd argument.
108-
, with_custodian_and_ward<1,2> >()
109-
)
104+
m.add(class_<A, bases<Base> >(no_init)
105+
.def("content", &A::content)
106+
.def("get_inner", &A::get_inner, return_internal_reference<>())
107+
)
108+
109+
.add(class_<inner>(no_init)
110+
.def("change", &inner::change)
111+
)
112+
113+
.add(class_<B>("B")
114+
.def_init(args<A*>(), with_custodian_and_ward_postcall<1,2>())
110115

111-
.def("a_content", &B::a_content)
116+
.def("adopt", &B::adopt
117+
// Adopt returns a pointer referring to a subobject of its 2nd argument (1st being "self")
118+
, return_internal_reference<2
119+
// Meanwhile, self holds a reference to the 2nd argument.
120+
, with_custodian_and_ward<1,2> >()
112121
)
122+
123+
.def("a_content", &B::a_content))
113124
;
114125
}
115126

127+
#include "module_tail.cpp"

test/test_pointer_adoption.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@
7070
>>> num_a_instances()
7171
0
7272
73+
>>> as_A(create('dynalloc')) is None
74+
0
75+
>>> base = Base()
76+
>>> as_A(base) is None
77+
1
7378
"""
7479
def run(args = None):
7580
import sys

0 commit comments

Comments
 (0)