Fixing setting this in Python when using __slots__

Don't attempt to use the class's __dict__ for setting 'this' when
a user has extended a class with:
    __slots__ = ['this'].
Was segfaulting. Now we fall back to a simple PyObject_SetAttr if the
usual approach to setting 'this' in __dict__ does not work.

Closes #1673 Closes #1674
This commit is contained in:
William S Fulton 2020-02-06 06:45:11 +00:00
parent a9731251a4
commit a01e8474f6
4 changed files with 46 additions and 15 deletions

View File

@ -7,6 +7,9 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.0.2 (in progress) Version 4.0.2 (in progress)
=========================== ===========================
2020-02-06: wsfulton
[Python] #1673 #1674 Fix setting 'this' when extending a proxy class with __slots__.
2020-01-31: vadz 2020-01-31: vadz
[Ruby] Add std::auto_ptr<> typemaps. [Ruby] Add std::auto_ptr<> typemaps.

View File

@ -21,3 +21,16 @@ if grabstaticpath() != None:
Test.static_func() Test.static_func()
if grabstaticpath() != os.path.basename(mypath): if grabstaticpath() != os.path.basename(mypath):
raise RuntimeError("grabstaticpath failed") raise RuntimeError("grabstaticpath failed")
# slots test
fs = ForSlots()
if fs.ValidVariable != 99:
raise RuntimeError("ValidVariable failed")
fs.ValidVariable = 11
if fs.ValidVariable != 11:
raise RuntimeError("ValidVariable failed")
try:
fs.Invalid = 22
raise RuntimeError("It should not be possible to set a random variable name")
except AttributeError:
pass

View File

@ -42,13 +42,31 @@ import os.path
%} %}
%inline %{ %inline %{
class Test { class Test {
public: public:
static void static_func() {}; static void static_func() {};
void funk() {}; void funk() {};
}; };
%}
// Github issue #1674
%extend ForSlots {
%pythoncode %{
__slots__ = ["this"]
%}
}
// While __slots__ does not contain 'ValidVariable' in the list, it is still possible
// to set 'ValidVariable'. A little odd, but the whole attribute setting is bypassed
// for setting C/C++ member variables.
// Not sure how to test the equivalent for -builtin.
%inline %{
struct ForSlots {
int ValidVariable;
ForSlots() : ValidVariable(99) {}
};
%}
%inline %{
#ifdef SWIGPYTHON_BUILTIN #ifdef SWIGPYTHON_BUILTIN
bool is_python_builtin() { return true; } bool is_python_builtin() { return true; }
#else #else

View File

@ -1248,22 +1248,19 @@ SWIG_Python_NewShadowInstance(SwigPyClientData *data, PyObject *swig_this)
SWIGRUNTIME void SWIGRUNTIME void
SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this) SWIG_Python_SetSwigThis(PyObject *inst, PyObject *swig_this)
{ {
PyObject *dict;
#if !defined(SWIG_PYTHON_SLOW_GETSET_THIS) #if !defined(SWIG_PYTHON_SLOW_GETSET_THIS)
PyObject **dictptr = _PyObject_GetDictPtr(inst); PyObject **dictptr = _PyObject_GetDictPtr(inst);
if (dictptr != NULL) { if (dictptr != NULL) {
dict = *dictptr; PyObject *dict = *dictptr;
if (dict == NULL) { if (dict == NULL) {
dict = PyDict_New(); dict = PyDict_New();
*dictptr = dict; *dictptr = dict;
} }
PyDict_SetItem(dict, SWIG_This(), swig_this); PyDict_SetItem(dict, SWIG_This(), swig_this);
return; return;
} }
#endif #endif
dict = PyObject_GetAttrString(inst, "__dict__"); PyObject_SetAttr(inst, SWIG_This(), swig_this);
PyDict_SetItem(dict, SWIG_This(), swig_this);
Py_DECREF(dict);
} }