Menu

#821 vectors __getitem__ and ref counting

None
closed-fixed
python (260)
5
2022-03-21
2007-04-25
No

I'm on swig-1.3.31.

The way vectors are wrapped, getting an item out of a vector will return an object that is effectively a wrapped pointer, but its validity depends on the lifespan of the vector.

v = vector()
item = v[3]
del v

# segfault
print item.foo

I didn't notice this being documented anywhere.

Note that this is the kind of code I was getting a crash on:

def get():
return vector()

# segfault
print get()[3].foo

Python optimistically decrefs the result of get() after calling __getitem__ but before __getattr__. It took me a while to understand this and realize why it was crashing.

I think the bug in all of this is that __getitem__ does not increase the reference count of the vector instance it is a member of, and python may choose to delete the vector while objects that refer to its memory still exist.

Ideally the object wrapping the result of v[3] would hold a reference to v to prevent this dangling pointer problem.

Discussion

  • Olly Betts

    Olly Betts - 2022-03-21
    • status: open --> closed-fixed
    • Group: -->
     
  • Olly Betts

    Olly Betts - 2022-03-21

    Seems to have been fixed since reporting as what's described above works with SWIG 4.0.2:

    $ cat test.i
    %module test
    %include std_vector.i
    %inline %{
    struct A { int foo = 0; };
    %}
    %template(vector) std::vector<A>;
    $ swig -c++ -python test.i
    $ g++ `python3-config --cflags` -fPIC -shared test_wrap.cxx -o _test.so
    $ python3
    Python 3.9.10 (main, Feb 22 2022, 13:54:07) 
    [GCC 11.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from test import *
    >>> v = vector(4)
    >>> item = v[3]
    >>> del v
    >>> print(item.foo)
    0
    >>> def get():
    ...     return vector(4)
    ... 
    >>> print(get()[3].foo)
    0
    
     

Log in to post a comment.