summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2020-01-08 10:44:20 +0000
committerStefan Behnel <stefan_ml@behnel.de>2020-01-08 11:44:20 +0100
commitc2d76d3201603385d4d9d4780e1f0257056e8363 (patch)
treeae14c8fdec53cd11ba4758474a802a2a8b8fb0af
parentdd64445f7b74338e911ead8c566e939a2d62cf52 (diff)
downloadcython-c2d76d3201603385d4d9d4780e1f0257056e8363.tar.gz
Fixed handling of kwds in generator closures (GH-3268)
-rw-r--r--Cython/Compiler/Nodes.py10
-rw-r--r--tests/run/generators.pyx34
2 files changed, 42 insertions, 2 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index d97c1cc2a..b3525584d 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -3256,8 +3256,14 @@ class DefNode(FuncDefNode):
def put_into_closure(entry):
if entry.in_closure:
code.putln('%s = %s;' % (entry.cname, entry.original_cname))
- code.put_var_incref(entry)
- code.put_var_giveref(entry)
+ if entry.xdecref_cleanup:
+ # mostly applies to the starstar arg - this can sometimes be NULL
+ # so must be xincrefed instead
+ code.put_var_xincref(entry)
+ code.put_var_xgiveref(entry)
+ else:
+ code.put_var_incref(entry)
+ code.put_var_giveref(entry)
for arg in self.args:
put_into_closure(arg.entry)
for arg in self.star_arg, self.starstar_arg:
diff --git a/tests/run/generators.pyx b/tests/run/generators.pyx
index f407739c8..1ba98fd8f 100644
--- a/tests/run/generators.pyx
+++ b/tests/run/generators.pyx
@@ -522,3 +522,37 @@ def test_generator_frame(a=1):
"""
b = a + 1
yield b
+
+# GH Issue 3265 - **kwds could cause a crash in some cases due to not
+# handling NULL pointers (in testing it shows as a REFNANNY error).
+# This was on creation of the generator and
+# doesn't really require it to be iterated through:
+def some_function():
+ return 0
+
+def test_generator_kwds1(**kwargs):
+ """
+ >>> for a in test_generator_kwds1():
+ ... print(a)
+ 0
+ """
+ yield some_function(**kwargs)
+
+def test_generator_kwds2(**kwargs):
+ """
+ >>> for a in test_generator_kwds2():
+ ... print(a)
+ 0
+ """
+ yield 0
+
+def test_generator_kwds3(**kwargs):
+ """
+ This didn't actually crash before but is still worth a try
+ >>> len(list(test_generator_kwds3()))
+ 0
+ >>> for a in test_generator_kwds3(a=1):
+ ... print(a)
+ a
+ """
+ yield from kwargs.keys()