Closed
Description
I've found a bug if a user tries to delete an attribute of a struct wrapped with SWIG.
Example interface file struct_del_member_segfault.i
:
%module struct_del_member_segfault
%inline %{
struct Foo {
int x;
};
%}
Extension built with setup.py
from distutils.core import setup, Extension
setup (name = 'struct_del_member_segfault',
ext_modules = [Extension(
'_struct_del_member_segfault',
sources=['struct_del_member_segfault_wrap.c'])],
py_modules = ["struct_del_member_segfault"],
)
Test file test.py
:
import struct_del_member_segfault
s = struct_del_member_segfault.Foo()
print('get member')
print(s.x)
print('set member')
s.x = 123
print('del member')
del s.x
Build and run:
$ swig -python -builtin -nofastunpack struct_del_member_segfault.i
$ python3 setup.py build_ext --inplace
running build_ext
building '_struct_del_member_segfault' extension
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g -DOPENSSL_LOAD_CONF -fwrapv -fno-semantic-interposition -fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g -fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g -fPIC -I/usr/include/python3.6m -c struct_del_member_segfault_wrap.c -o build/temp.linux-x86_64-3.6/struct_del_member_segfault_wrap.o
gcc -pthread -shared build/temp.linux-x86_64-3.6/struct_del_member_segfault_wrap.o -L/usr/lib64 -lpython3.6m -o /home/jim/Documents/projects/swig/bugs/struct_del_member_segfault/_struct_del_member_segfault.cpython-36m-x86_64-linux-gnu.so
$ python3 test.py
get member
0
set member
del member
Segmentation fault (core dumped)
If I omit the -nofastunpack
option I get a slightly better result:
$ python3 test.py
get member
0
set member
del member
Traceback (most recent call last):
File "test.py", line 9, in <module>
del s.x
SystemError: error return without exception set
The segfault occurs in SwigPyBuiltin_SetterClosure
, which is passed a NULL
value to delete the attribute. It calls SWIG_Py_INCREF
on the NULL
, causing a segfault.
A possible cure is to add the following to SwigPyBuiltin_SetterClosure
and SwigPyBuiltin_FunpackSetterClosure
:
if (!val) {
PyErr_Format(PyExc_TypeError, "Illegal member variable deletion in type '%.300s'", obj->ob_type->tp_name);
return -1;
}
Metadata
Metadata
Assignees
Labels
No labels