Discussion:
[Cython] Compiler crash: forward declaration of cdef class with "public" attributes
Alok Singhal
2014-07-08 23:34:53 UTC
Permalink
Hi,

I am getting a compiler crash with the following code:

$ cat foo.pxd
cdef class Foo:
cdef public object x
$ cat foo.pyx
cdef class Foo

cdef class Foo:
pass
$ ./cython.py foo.pyx

Error compiling Cython file:
------------------------------------------------------------
...
cdef class Foo
^
------------------------------------------------------------

foo.pyx:1:5: Compiler crash in AnalyseDeclarationsTransform

ModuleNode.body = StatListNode(foo.pyx:1:0)
StatListNode.stats[0] = CClassDefNode(foo.pyx:1:5,
as_name = u'Foo',
class_name = u'Foo',
module_name = '',
visibility = 'private')

Compiler crash traceback from this point on:
File "/Users/alok/Downloads/repos/cython.git/Cython/Compiler/Visitor.py",
line 173, in _visit
return handler_method(obj)
File
"/Users/alok/Downloads/repos/cython.git/Cython/Compiler/ParseTreeTransforms.py",
line 1478, in visit_CClassDefNode
node.body.stats += stats
AttributeError: 'NoneType' object has no attribute 'stats'

The problem seems to be due to having a .pxd file with the attributes of
the cdef class in it. Since the attributes are declared "public", Cython
is trying to generate property code for "Foo.x". But it's trying to do
that at the point of forward declaration in the .pyx file, instead of the
definition of the class.

An easy fix seems to be to change
AnalyseDeclarationsTransform.visit_CClassDefNode in ParseTreeTransforms.py
to check for node.body not being none. I.e., the following patch seems to
work:

diff --git a/Cython/Compiler/ParseTreeTransforms.py
b/Cython/Compiler/ParseTreeTransforms.py
index f8c2efa..7811d56 100644
--- a/Cython/Compiler/ParseTreeTransforms.py
+++ b/Cython/Compiler/ParseTreeTransforms.py
@@ -1466,7 +1466,7 @@ if VALUE is not None:

def visit_CClassDefNode(self, node):
node = self.visit_ClassDefNode(node)
- if node.scope and node.scope.implemented:
+ if node.body and node.scope and node.scope.implemented:
stats = []
for entry in node.scope.var_entries:
if entry.needs_property:

Thanks,
Alok
Robert Bradshaw
2014-07-23 06:42:24 UTC
Permalink
Post by Alok Singhal
Hi,
$ cat foo.pxd
cdef public object x
$ cat foo.pyx
cdef class Foo
pass
$ ./cython.py foo.pyx
------------------------------------------------------------
...
cdef class Foo
^
------------------------------------------------------------
foo.pyx:1:5: Compiler crash in AnalyseDeclarationsTransform
ModuleNode.body = StatListNode(foo.pyx:1:0)
StatListNode.stats[0] = CClassDefNode(foo.pyx:1:5,
as_name = u'Foo',
class_name = u'Foo',
module_name = '',
visibility = 'private')
File "/Users/alok/Downloads/repos/cython.git/Cython/Compiler/Visitor.py",
line 173, in _visit
return handler_method(obj)
File
"/Users/alok/Downloads/repos/cython.git/Cython/Compiler/ParseTreeTransforms.py",
line 1478, in visit_CClassDefNode
node.body.stats += stats
AttributeError: 'NoneType' object has no attribute 'stats'
The problem seems to be due to having a .pxd file with the attributes of the
cdef class in it. Since the attributes are declared "public", Cython is
trying to generate property code for "Foo.x". But it's trying to do that at
the point of forward declaration in the .pyx file, instead of the definition
of the class.
An easy fix seems to be to change
AnalyseDeclarationsTransform.visit_CClassDefNode in ParseTreeTransforms.py
to check for node.body not being none. I.e., the following patch seems to
diff --git a/Cython/Compiler/ParseTreeTransforms.py
b/Cython/Compiler/ParseTreeTransforms.py
index f8c2efa..7811d56 100644
--- a/Cython/Compiler/ParseTreeTransforms.py
+++ b/Cython/Compiler/ParseTreeTransforms.py
node = self.visit_ClassDefNode(node)
stats = []
Thanks,
Alok
Thanks. https://github.com/cython/cython/commit/967c8e11da94ddae1ea7f1524f6beef2e030c4d9

FWIW, forward declarations should not generally be needed, and
certainly not needed if the class is already declared in a pxd file.
Alok Singhal
2014-07-23 07:29:50 UTC
Permalink
Post by Robert Bradshaw
Thanks. https://github.com/cython/cython/commit/967c8e11da94ddae1ea7f1524f6beef2e030c4d9
Thanks for the fix!
Post by Robert Bradshaw
FWIW, forward declarations should not generally be needed, and
certainly not needed if the class is already declared in a pxd file.
I encountered this problem because we have a tool that generates .pxd
files automatically from a .pyx file, and that tool ends up generating
code like this in certain cases.

Also, if forward declarations are not recommended, what is the best
way to declare two cdef classes that need to know about each other?
(Short of "don't do that!" :-) ).

Thanks,
Alok
Robert Bradshaw
2014-07-23 15:28:41 UTC
Permalink
Post by Alok Singhal
Post by Robert Bradshaw
Thanks. https://github.com/cython/cython/commit/967c8e11da94ddae1ea7f1524f6beef2e030c4d9
Thanks for the fix!
Post by Robert Bradshaw
FWIW, forward declarations should not generally be needed, and
certainly not needed if the class is already declared in a pxd file.
I encountered this problem because we have a tool that generates .pxd
files automatically from a .pyx file, and that tool ends up generating
code like this in certain cases.
Also, if forward declarations are not recommended, what is the best
way to declare two cdef classes that need to know about each other?
(Short of "don't do that!" :-) ).
Just do it without the forward declarations.

- Robert
Alok Singhal
2014-07-23 16:34:37 UTC
Permalink
Post by Robert Bradshaw
Post by Alok Singhal
Also, if forward declarations are not recommended, what is the best
way to declare two cdef classes that need to know about each other?
(Short of "don't do that!" :-) ).
Just do it without the forward declarations.
Thanks! I didn't realize that I didn't need forward declarations.

-Alok

Loading...