summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>2023-09-20 23:08:06 (GMT)
committerGitHub <noreply@github.com>2023-09-20 23:08:06 (GMT)
commit9ccf0545efd5bc5af5aa51774030c471d49a972b (patch)
treeb55fefefa886638de6a493944674b0e053089a3f
parent14cdefa667f211401c9dfab33c4695e80b4e5e95 (diff)
downloadcpython-9ccf0545efd5bc5af5aa51774030c471d49a972b.zip
cpython-9ccf0545efd5bc5af5aa51774030c471d49a972b.tar.gz
cpython-9ccf0545efd5bc5af5aa51774030c471d49a972b.tar.bz2
gh-109627: duplicated smalll exit blocks need to be assigned jump target labels (#109630)
-rw-r--r--Lib/test/test_compile.py9
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst2
-rw-r--r--Python/flowgraph.c22
3 files changed, 28 insertions, 5 deletions
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 39d972c..f4e2855 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1252,6 +1252,15 @@ class TestSpecifics(unittest.TestCase):
return a, b
self.assertEqual(f(), (54, 96))
+ def test_duplicated_small_exit_block(self):
+ # See gh-109627
+ def f():
+ while element and something:
+ try:
+ return something
+ except:
+ pass
+
@requires_debug_ranges()
class TestSourcePositions(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst
new file mode 100644
index 0000000..397d76e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-20-23-04-15.gh-issue-109627.xxe7De.rst
@@ -0,0 +1,2 @@
+Fix bug where the compiler does not assign a new jump target label to a
+duplicated small exit block.
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index 5ad4991..2df9b48 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -575,16 +575,23 @@ check_cfg(cfg_builder *g) {
return SUCCESS;
}
-/* Calculate the actual jump target from the target_label */
static int
-translate_jump_labels_to_targets(basicblock *entryblock)
+get_max_label(basicblock *entryblock)
{
- int max_label = -1;
+ int lbl = -1;
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- if (b->b_label.id > max_label) {
- max_label = b->b_label.id;
+ if (b->b_label.id > lbl) {
+ lbl = b->b_label.id;
}
}
+ return lbl;
+}
+
+/* Calculate the actual jump target from the target_label */
+static int
+translate_jump_labels_to_targets(basicblock *entryblock)
+{
+ int max_label = get_max_label(entryblock);
size_t mapsize = sizeof(basicblock *) * (max_label + 1);
basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize);
if (!label2block) {
@@ -2229,6 +2236,7 @@ is_exit_without_lineno(basicblock *b) {
return true;
}
+
/* PEP 626 mandates that the f_lineno of a frame is correct
* after a frame terminates. It would be prohibitively expensive
* to continuously update the f_lineno field at runtime,
@@ -2242,6 +2250,9 @@ static int
duplicate_exits_without_lineno(cfg_builder *g)
{
assert(no_empty_basic_blocks(g));
+
+ int next_lbl = get_max_label(g->g_entryblock) + 1;
+
/* Copy all exit blocks without line number that are targets of a jump.
*/
basicblock *entryblock = g->g_entryblock;
@@ -2260,6 +2271,7 @@ duplicate_exits_without_lineno(cfg_builder *g)
target->b_predecessors--;
new_target->b_predecessors = 1;
new_target->b_next = target->b_next;
+ new_target->b_label.id = next_lbl++;
target->b_next = new_target;
}
}