]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-143055: Fix crash in AST unparser when unparsing dict comprehension unpacking...
authorStan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Mon, 9 Mar 2026 17:37:23 +0000 (17:37 +0000)
committerGitHub <noreply@github.com>
Mon, 9 Mar 2026 17:37:23 +0000 (10:37 -0700)
Doc/conf.py
Lib/_ast_unparse.py
Lib/test/test_future_stmt/test_future.py
Lib/test/test_unparse.py
Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-16-16-17.gh-issue-143055.qDUFlY.rst [new file with mode: 0644]
Python/ast_unparse.c

index 26497083d28e47521e93f38629af00fdd9fb652b..6f66ed68c52e83c9f7a49e6191d1d1f566bdd228 100644 (file)
@@ -557,6 +557,7 @@ linkcheck_ignore = [
 # mapping unique short aliases to a base URL and a prefix.
 # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
 extlinks = {
+    "oss-fuzz": ("https://issues.oss-fuzz.com/issues/%s", "#%s"),
     "pypi": ("https://pypi.org/project/%s/", "%s"),
     "source": (SOURCE_URI, "%s"),
 }
index 0c3b1d3a9108a3ad8c71ac99c25d172e10940767..916bb25d74dee9ba00a89cab64192edb2893fba4 100644 (file)
@@ -738,9 +738,13 @@ class Unparser(NodeVisitor):
 
     def visit_DictComp(self, node):
         with self.delimit("{", "}"):
-            self.traverse(node.key)
-            self.write(": ")
-            self.traverse(node.value)
+            if node.value:
+                self.traverse(node.key)
+                self.write(": ")
+                self.traverse(node.value)
+            else:
+                self.write("**")
+                self.traverse(node.key)
             for gen in node.generators:
                 self.traverse(gen)
 
index 71f1e616116d81bb52f17ebb36442dba923fc36b..faa3a2bfe121dc6c924936c08469b392eaf9b89b 100644 (file)
@@ -349,6 +349,8 @@ class AnnotationsFutureTestCase(unittest.TestCase):
         eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))")
         eq("{i: 0 for i in (1, 2, 3)}")
         eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}")
+        eq("{**x for x in ()}")
+        eq("[*x for x in ()]")
         eq("[(x, y) for x, y in (a, b)]")
         eq("[(x,) for x, in (a,)]")
         eq("Python3 > Python2 > COBOL")
index 35e4652a87b423cf28166b2dd9ddd2f1c8d5318d..dcaad49ffab5d2669511e93929a98fbedf487c1d 100644 (file)
@@ -403,6 +403,11 @@ class UnparseTestCase(ASTTestCase):
     def test_dict_comprehension(self):
         self.check_ast_roundtrip("{x: x*x for x in range(10)}")
 
+    def test_dict_comprehension_unpacking(self):
+        self.check_ast_roundtrip("{**x for x in ()}")
+        self.check_ast_roundtrip("{**x for x in range(10)}")
+        self.check_ast_roundtrip("[*x for x in ()]")
+
     def test_class_decorators(self):
         self.check_ast_roundtrip(class_decorator)
 
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-16-16-17.gh-issue-143055.qDUFlY.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-16-16-17.gh-issue-143055.qDUFlY.rst
new file mode 100644 (file)
index 0000000..9b55459
--- /dev/null
@@ -0,0 +1,2 @@
+Fix crash in AST unparser when unparsing dict comprehension unpacking.
+Found by OSS Fuzz in :oss-fuzz:`489790200`.
index c25699978cf6511f3bd6810b71228a63cc75fcc1..6050c351cff68f0138b968dfc0826a288d99a87c 100644 (file)
@@ -464,9 +464,15 @@ static int
 append_ast_dictcomp(PyUnicodeWriter *writer, expr_ty e)
 {
     APPEND_CHAR('{');
-    APPEND_EXPR(e->v.DictComp.key, PR_TEST);
-    APPEND_STR(": ");
-    APPEND_EXPR(e->v.DictComp.value, PR_TEST);
+    if (e->v.DictComp.value) {
+        APPEND_EXPR(e->v.DictComp.key, PR_TEST);
+        APPEND_STR(": ");
+        APPEND_EXPR(e->v.DictComp.value, PR_TEST);
+    }
+    else {
+        APPEND_STR("**");
+        APPEND_EXPR(e->v.DictComp.key, PR_TEST);
+    }
     APPEND(comprehensions, e->v.DictComp.generators);
     APPEND_CHAR_FINISH('}');
 }