Also fixes li_std_vector_enum testcase when run with -threads.
Patch supplied on swig-devel mailing list on 12 Sep with details...
==============================================
I just wanted to mention that I found a crash issue in bug..
I am using SWIG 2.0.11 with python and have –threads enabled. I have a C++ std::vector that I instantiate in SWIG with %template. I also have a method in a class that returns this vector. I also include std_vector.i, btw..
When I iterate like so:
children = Action.getActionList()
for child in children:
pass
Everything is fine..
When I iterate like this:
for child in Action.getActionList()
pass
Product crashes.
The problem is the following. This code gets called first:
SWIGINTERN PyObject *_wrap_delete_SwigPyIterator(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
swig::SwigPyIterator *arg1 = (swig::SwigPyIterator *) 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
PyObject * obj0 = 0 ;
if(!PyArg_UnpackTuple(args,(char *)"delete_SwigPyIterator",1,1,&obj0)) SWIG_fail;
res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_swig__SwigPyIterator, SWIG_POINTER_DISOWN | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_SwigPyIterator" "', argument " "1"" of type '" "swig::SwigPyIterator *""'");
}
arg1 = reinterpret_cast< swig::SwigPyIterator * >(argp1);
{
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
delete arg1;
SWIG_PYTHON_THREAD_END_ALLOW;
}
resultobj = SWIG_Py_Void();
return resultobj;
fail:
return NULL;
}
Note the SWIG_PYTHON_THREAD_BEGIN_ALLOW/END_ALLOW. In between those two statements, we delete arg1. That in turn will eventually end up in this code:
namespace swig {
class SwigPtr_PyObject {
protected:
PyObject *_obj;
public:
… snip! …
~SwigPtr_PyObject()
{
Py_XDECREF(_obj);
}
Uh-oh! We call Py_XDECREF when we aren’t supposed to because we are in a SWIG_PYTHON_THREAD_BEGIN_ALLOW/END_ALLOW section!
This takes care of the issue:
namespace swig {
class SwigPtr_PyObject {
protected:
PyObject *_obj;
public:
… snip! …
~SwigPtr_PyObject()
{
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
Py_XDECREF(_obj);
SWIG_PYTHON_THREAD_END_BLOCK;
}
There are several other methods in this class that use the Python API, but don’t have the BEGIN/END block defined. I’m not sure if they are required for all of them, but I believe they are..
I have attached a modified pyclasses.swg with what I believe are the correct changes. This code is from 2.0.11, but as far as I can tell, it’s the same as what is in 3.0.2…
Apologies for not doing more here (making/running tests, getting it in the code repository, etc..), but I’m under some pressure to get some unrelated things done…
157 lines
3.4 KiB
Text
157 lines
3.4 KiB
Text
#ifdef __cplusplus
|
|
|
|
/*
|
|
SwigPtr_PyObject is used as a replacement of PyObject *, where
|
|
the INCREF/DECREF are applied as needed.
|
|
|
|
You can use SwigPtr_PyObject in a container, such as
|
|
|
|
std::vector<SwigPtr_PyObject>;
|
|
|
|
or as a member variable:
|
|
|
|
struct A {
|
|
SwigPtr_PyObject obj;
|
|
A(PyObject *o) : _obj(o) {
|
|
}
|
|
};
|
|
|
|
or as a input/output value
|
|
|
|
SwigPtr_PyObject func(SwigPtr_PyObject obj) {
|
|
SwigPtr_PyObject out = PyString_FromFormat("hello %s", PyObject_AsString(obj));
|
|
Py_DECREF(out);
|
|
return out;
|
|
}
|
|
|
|
just remember to pair the object creation with the proper DECREF,
|
|
the same as with plain PyObject *ptr, since SwigPtr_PyObject always add
|
|
one reference at construction.
|
|
|
|
SwigPtr_PyObject is 'visible' at the wrapped side, so you can do:
|
|
|
|
|
|
%template(pyvector) std::vector<swig::SwigPtr_PyObject>;
|
|
|
|
and all the proper typemaps will be used.
|
|
|
|
*/
|
|
|
|
namespace swig {
|
|
%ignore SwigPtr_PyObject;
|
|
struct SwigPtr_PyObject {};
|
|
%apply PyObject * {SwigPtr_PyObject};
|
|
%apply PyObject * const& {SwigPtr_PyObject const&};
|
|
|
|
%typemap(typecheck,precedence=SWIG_TYPECHECK_SWIGOBJECT,noblock=1) SwigPtr_PyObject const& "$1 = ($input != 0);";
|
|
|
|
|
|
/* For output */
|
|
%typemap(out,noblock=1) SwigPtr_PyObject {
|
|
$result = (PyObject *)$1;
|
|
Py_INCREF($result);
|
|
}
|
|
|
|
%typemap(out,noblock=1) SwigPtr_PyObject const & {
|
|
$result = (PyObject *)*$1;
|
|
Py_INCREF($result);
|
|
}
|
|
|
|
}
|
|
|
|
%{
|
|
namespace swig {
|
|
class SwigPtr_PyObject {
|
|
protected:
|
|
PyObject *_obj;
|
|
|
|
public:
|
|
SwigPtr_PyObject() :_obj(0)
|
|
{
|
|
}
|
|
|
|
SwigPtr_PyObject(const SwigPtr_PyObject& item) : _obj(item._obj)
|
|
{
|
|
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
|
|
Py_XINCREF(_obj);
|
|
SWIG_PYTHON_THREAD_END_BLOCK;
|
|
}
|
|
|
|
SwigPtr_PyObject(PyObject *obj, bool initial_ref = true) :_obj(obj)
|
|
{
|
|
if (initial_ref) {
|
|
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
|
|
Py_XINCREF(_obj);
|
|
SWIG_PYTHON_THREAD_END_BLOCK;
|
|
}
|
|
}
|
|
|
|
SwigPtr_PyObject & operator=(const SwigPtr_PyObject& item)
|
|
{
|
|
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
|
|
Py_XINCREF(item._obj);
|
|
Py_XDECREF(_obj);
|
|
_obj = item._obj;
|
|
SWIG_PYTHON_THREAD_END_BLOCK;
|
|
return *this;
|
|
}
|
|
|
|
~SwigPtr_PyObject()
|
|
{
|
|
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
|
|
Py_XDECREF(_obj);
|
|
SWIG_PYTHON_THREAD_END_BLOCK;
|
|
}
|
|
|
|
operator PyObject *() const
|
|
{
|
|
return _obj;
|
|
}
|
|
|
|
PyObject *operator->() const
|
|
{
|
|
return _obj;
|
|
}
|
|
};
|
|
}
|
|
%}
|
|
|
|
/*
|
|
SwigVar_PyObject is used to manage 'in the scope' PyObject * variables,
|
|
as in
|
|
|
|
int func () {
|
|
SwigVar_PyObject obj = PyString_FromString("hello");
|
|
}
|
|
|
|
ie, 'obj' is created and destructed in the same scope from
|
|
a python object that carries at least one reference value.
|
|
|
|
SwigVar_PyObject just take care of applying the proper Py_DECREF.
|
|
|
|
Hence, this class is purely internal and not visible at the wrapped side.
|
|
*/
|
|
namespace swig {
|
|
%ignore SwigVar_PyObject;
|
|
struct SwigVar_PyObject {};
|
|
%apply PyObject * {SwigVar_PyObject};
|
|
%apply PyObject * const& {SwigVar_PyObject const&};
|
|
}
|
|
|
|
%{
|
|
namespace swig {
|
|
struct SwigVar_PyObject : SwigPtr_PyObject {
|
|
SwigVar_PyObject(PyObject* obj = 0) : SwigPtr_PyObject(obj, false) { }
|
|
|
|
SwigVar_PyObject & operator = (PyObject* obj)
|
|
{
|
|
Py_XDECREF(_obj);
|
|
_obj = obj;
|
|
return *this;
|
|
}
|
|
};
|
|
}
|
|
%}
|
|
|
|
|
|
#endif
|