https://github.com/python/cpython/commit/255e79fa955ac5ffef9eb27087e8b1373e98e3bd
commit: 255e79fa955ac5ffef9eb27087e8b1373e98e3bd
branch: main
author: Stan Ulbrych <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2026-03-09T10:37:23-07:00
summary:

gh-143055: Fix crash in AST unparser when unparsing dict comprehension 
unpacking (#145556)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-16-16-17.gh-issue-143055.qDUFlY.rst
M Doc/conf.py
M Lib/_ast_unparse.py
M Lib/test/test_future_stmt/test_future.py
M Lib/test/test_unparse.py
M Python/ast_unparse.c

diff --git a/Doc/conf.py b/Doc/conf.py
index 26497083d28e47..6f66ed68c52e83 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -557,6 +557,7 @@
 # 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"),
 }
diff --git a/Lib/_ast_unparse.py b/Lib/_ast_unparse.py
index 0c3b1d3a9108a3..916bb25d74dee9 100644
--- a/Lib/_ast_unparse.py
+++ b/Lib/_ast_unparse.py
@@ -738,9 +738,13 @@ def visit_SetComp(self, node):
 
     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)
 
diff --git a/Lib/test/test_future_stmt/test_future.py 
b/Lib/test/test_future_stmt/test_future.py
index 71f1e616116d81..faa3a2bfe121dc 100644
--- a/Lib/test/test_future_stmt/test_future.py
+++ b/Lib/test/test_future_stmt/test_future.py
@@ -349,6 +349,8 @@ def test_annotations(self):
         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")
diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py
index 35e4652a87b423..dcaad49ffab5d2 100644
--- a/Lib/test/test_unparse.py
+++ b/Lib/test/test_unparse.py
@@ -403,6 +403,11 @@ def test_set_comprehension(self):
     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
index 00000000000000..9b55459bffdea8
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-16-16-17.gh-issue-143055.qDUFlY.rst
@@ -0,0 +1,2 @@
+Fix crash in AST unparser when unparsing dict comprehension unpacking.
+Found by OSS Fuzz in :oss-fuzz:`489790200`.
diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c
index c25699978cf651..6050c351cff68f 100644
--- a/Python/ast_unparse.c
+++ b/Python/ast_unparse.c
@@ -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('}');
 }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to