[Cython] [cython-users] Test case that will segfault
Stefan Behnel
stefan_ml at behnel.de
Sat Nov 17 12:31:54 CET 2012
Stefan Behnel, 17.11.2012 12:08:
> Ewald de Wit, 16.11.2012 23:09:
>> I have attached some code below that will lead to a segmentation fault on
>> Linux. The code iterates over a linked list of nodes and removes a node
>> while doing so. Adding an extra ref to the removed node will prevent the
>> crash, so the problem might be a refcount going to zero before its time.
>> This is with Cython 0.17.1 - not sure if bug or known limitation.
>> -------------------------------------------------------------------------------------------------------------------------
>> cdef class Node:
>>
>> cdef public int value
>> cdef public Node nextNode
>>
>> def __init__(self, value):
>> self.value = value
>> self.nextNode = None
>>
>>
>> cdef class Chain:
>>
>> cdef public Node firstNode
>>
>> def __init__(self):
>> self.firstNode = None
>
> Note that Python object attributes are automatically initialised to None,
> so the above line is redundant.
>
>
>> def __iter__(self):
>> n = self.firstNode
>> while n is not None:
>> yield n
>> n = n.nextNode
>>
>> def add(self, Node node):
>> if self.firstNode is None:
>> self.firstNode = node
>> else:
>> for n in self: pass
>> n.nextNode = node
>>
>> def remove(self, Node node):
>> if node is self.firstNode:
>> self.firstNode = node.nextNode
>> else:
>> for n in self:
>> if node is n.nextNode:
>> n.nextNode = node.nextNode
>> break
>>
>> def dump(self):
>> for n in self:
>> print n.value
>>
>>
>> def test():
>> c = Chain()
>> c.add(Node(1))
>> c.add(Node(2))
>> c.add(Node(3))
>> c.add(Node(4))
>> n = c.firstNode
>> while n is not None:
>> if n.value == 3:
>> c.remove(n)
>> #nn = n # Adding extra ref will prevent crash
>> n = n.nextNode # Crash will happen here at value 3
>
> The C code generated for the last line is as follows:
>
> __Pyx_INCREF(((PyObject *)__pyx_v_n->nextNode));
> __Pyx_DECREF(((PyObject *)__pyx_v_n));
> __pyx_v_n = __pyx_v_n->nextNode;
>
> That's definitely unhealthy code. For a test case, the following would be
> enough:
>
> """
> cdef class Node:
> cdef public Node next
>
> def test():
> cdef Node n = Node()
> n.next = Node()
> n = n.next
>
> test()
> """
>
> However, this doesn't crash for me, likely because the DECREF() above
> doesn't free the memory, just release it to CPython's memory allocator. So
> we're just lucky here.
Here is a proposed fix:
https://github.com/cython/cython/commit/ea6a71acb5c79afb080855be1cb6ca30d283ec25
If Jenkins is happy with it, I'll add it to the release branch for 0.17.2.
Stefan
More information about the cython-devel
mailing list