Skip to content

Commit 255e79f

Browse files
gh-143055: Fix crash in AST unparser when unparsing dict comprehension unpacking (#145556)
1 parent d76df75 commit 255e79f

File tree

6 files changed

+26
-6
lines changed

6 files changed

+26
-6
lines changed

Doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@
557557
# mapping unique short aliases to a base URL and a prefix.
558558
# https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html
559559
extlinks = {
560+
"oss-fuzz": ("https://issues.oss-fuzz.com/issues/%s", "#%s"),
560561
"pypi": ("https://pypi.org/project/%s/", "%s"),
561562
"source": (SOURCE_URI, "%s"),
562563
}

Lib/_ast_unparse.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -738,9 +738,13 @@ def visit_SetComp(self, node):
738738

739739
def visit_DictComp(self, node):
740740
with self.delimit("{", "}"):
741-
self.traverse(node.key)
742-
self.write(": ")
743-
self.traverse(node.value)
741+
if node.value:
742+
self.traverse(node.key)
743+
self.write(": ")
744+
self.traverse(node.value)
745+
else:
746+
self.write("**")
747+
self.traverse(node.key)
744748
for gen in node.generators:
745749
self.traverse(gen)
746750

Lib/test/test_future_stmt/test_future.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ def test_annotations(self):
349349
eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))")
350350
eq("{i: 0 for i in (1, 2, 3)}")
351351
eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}")
352+
eq("{**x for x in ()}")
353+
eq("[*x for x in ()]")
352354
eq("[(x, y) for x, y in (a, b)]")
353355
eq("[(x,) for x, in (a,)]")
354356
eq("Python3 > Python2 > COBOL")

Lib/test/test_unparse.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,11 @@ def test_set_comprehension(self):
403403
def test_dict_comprehension(self):
404404
self.check_ast_roundtrip("{x: x*x for x in range(10)}")
405405

406+
def test_dict_comprehension_unpacking(self):
407+
self.check_ast_roundtrip("{**x for x in ()}")
408+
self.check_ast_roundtrip("{**x for x in range(10)}")
409+
self.check_ast_roundtrip("[*x for x in ()]")
410+
406411
def test_class_decorators(self):
407412
self.check_ast_roundtrip(class_decorator)
408413

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash in AST unparser when unparsing dict comprehension unpacking.
2+
Found by OSS Fuzz in :oss-fuzz:`489790200`.

Python/ast_unparse.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,15 @@ static int
464464
append_ast_dictcomp(PyUnicodeWriter *writer, expr_ty e)
465465
{
466466
APPEND_CHAR('{');
467-
APPEND_EXPR(e->v.DictComp.key, PR_TEST);
468-
APPEND_STR(": ");
469-
APPEND_EXPR(e->v.DictComp.value, PR_TEST);
467+
if (e->v.DictComp.value) {
468+
APPEND_EXPR(e->v.DictComp.key, PR_TEST);
469+
APPEND_STR(": ");
470+
APPEND_EXPR(e->v.DictComp.value, PR_TEST);
471+
}
472+
else {
473+
APPEND_STR("**");
474+
APPEND_EXPR(e->v.DictComp.key, PR_TEST);
475+
}
470476
APPEND(comprehensions, e->v.DictComp.generators);
471477
APPEND_CHAR_FINISH('}');
472478
}

0 commit comments

Comments
 (0)