Skip to content

Commit 02b30a8

Browse files
authored
[3.11] GH-94438: Backport GH-94444 (#94486)
* Account for NULLs on evaluation stack when jumping lines.
1 parent 9fa9661 commit 02b30a8

File tree

3 files changed

+98
-17
lines changed

3 files changed

+98
-17
lines changed

Lib/test/test_sys_settrace.py

+61-4
Original file line numberDiff line numberDiff line change
@@ -2264,25 +2264,25 @@ async def test_no_jump_backwards_into_async_for_block(output):
22642264
output.append(2)
22652265
output.append(3)
22662266

2267-
@jump_test(1, 3, [], (ValueError, 'depth'))
2267+
@jump_test(1, 3, [], (ValueError, 'stack'))
22682268
def test_no_jump_forwards_into_with_block(output):
22692269
output.append(1)
22702270
with tracecontext(output, 2):
22712271
output.append(3)
22722272

2273-
@async_jump_test(1, 3, [], (ValueError, 'depth'))
2273+
@async_jump_test(1, 3, [], (ValueError, 'stack'))
22742274
async def test_no_jump_forwards_into_async_with_block(output):
22752275
output.append(1)
22762276
async with asynctracecontext(output, 2):
22772277
output.append(3)
22782278

2279-
@jump_test(3, 2, [1, 2, -1], (ValueError, 'depth'))
2279+
@jump_test(3, 2, [1, 2, -1], (ValueError, 'stack'))
22802280
def test_no_jump_backwards_into_with_block(output):
22812281
with tracecontext(output, 1):
22822282
output.append(2)
22832283
output.append(3)
22842284

2285-
@async_jump_test(3, 2, [1, 2, -1], (ValueError, 'depth'))
2285+
@async_jump_test(3, 2, [1, 2, -1], (ValueError, 'stack'))
22862286
async def test_no_jump_backwards_into_async_with_block(output):
22872287
async with asynctracecontext(output, 1):
22882288
output.append(2)
@@ -2584,6 +2584,63 @@ async def test_jump_backward_over_async_listcomp_v2(output):
25842584
output.append(7)
25852585
output.append(8)
25862586

2587+
# checking for segfaults.
2588+
@jump_test(3, 7, [], error=(ValueError, "stack"))
2589+
def test_jump_with_null_on_stack_load_global(output):
2590+
a = 1
2591+
print(
2592+
output.append(3)
2593+
)
2594+
output.append(5)
2595+
(
2596+
( # 7
2597+
a
2598+
+
2599+
10
2600+
)
2601+
+
2602+
13
2603+
)
2604+
output.append(15)
2605+
2606+
# checking for segfaults.
2607+
@jump_test(4, 8, [], error=(ValueError, "stack"))
2608+
def test_jump_with_null_on_stack_push_null(output):
2609+
a = 1
2610+
f = print
2611+
f(
2612+
output.append(4)
2613+
)
2614+
output.append(6)
2615+
(
2616+
( # 8
2617+
a
2618+
+
2619+
11
2620+
)
2621+
+
2622+
14
2623+
)
2624+
output.append(16)
2625+
2626+
# checking for segfaults.
2627+
@jump_test(3, 7, [], error=(ValueError, "stack"))
2628+
def test_jump_with_null_on_stack_load_attr(output):
2629+
a = 1
2630+
list.append(
2631+
output, 3
2632+
)
2633+
output.append(5)
2634+
(
2635+
( # 7
2636+
a
2637+
+
2638+
10
2639+
)
2640+
+
2641+
13
2642+
)
2643+
output.append(15)
25872644

25882645
class TestExtendedArgs(unittest.TestCase):
25892646

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Account for instructions that can push NULL to the stack when setting line
2+
number in a frame. Prevents some (unlikely) crashes.

Objects/frameobject.c

+35-13
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,24 @@ typedef enum kind {
137137
Iterator = 1,
138138
Except = 2,
139139
Object = 3,
140+
Null = 4,
140141
} Kind;
141142

142-
#define BITS_PER_BLOCK 2
143+
static int
144+
compatible_kind(Kind from, Kind to) {
145+
if (to == 0) {
146+
return 0;
147+
}
148+
if (to == Object) {
149+
return from != Null;
150+
}
151+
if (to == Null) {
152+
return 1;
153+
}
154+
return from == to;
155+
}
156+
157+
#define BITS_PER_BLOCK 3
143158

144159
#define UNINITIALIZED -2
145160
#define OVERFLOWED -1
@@ -298,6 +313,23 @@ mark_stacks(PyCodeObject *code_obj, int len)
298313
case RERAISE:
299314
/* End of block */
300315
break;
316+
case PUSH_NULL:
317+
next_stack = push_value(next_stack, Null);
318+
stacks[i+1] = next_stack;
319+
break;
320+
case LOAD_GLOBAL:
321+
if (_Py_OPARG(code[i]) & 1) {
322+
next_stack = push_value(next_stack, Null);
323+
}
324+
next_stack = push_value(next_stack, Object);
325+
stacks[i+1] = next_stack;
326+
break;
327+
case LOAD_METHOD:
328+
next_stack = pop_value(next_stack);
329+
next_stack = push_value(next_stack, Null);
330+
next_stack = push_value(next_stack, Object);
331+
stacks[i+1] = next_stack;
332+
break;
301333
default:
302334
{
303335
int delta = PyCompile_OpcodeStackEffect(opcode, _Py_OPARG(code[i]));
@@ -318,17 +350,6 @@ mark_stacks(PyCodeObject *code_obj, int len)
318350
return stacks;
319351
}
320352

321-
static int
322-
compatible_kind(Kind from, Kind to) {
323-
if (to == 0) {
324-
return 0;
325-
}
326-
if (to == Object) {
327-
return 1;
328-
}
329-
return from == to;
330-
}
331-
332353
static int
333354
compatible_stack(int64_t from_stack, int64_t to_stack)
334355
{
@@ -365,7 +386,8 @@ explain_incompatible_stack(int64_t to_stack)
365386
case Except:
366387
return "can't jump into an 'except' block as there's no exception";
367388
case Object:
368-
return "differing stack depth";
389+
case Null:
390+
return "incompatible stacks";
369391
case Iterator:
370392
return "can't jump into the body of a for loop";
371393
default:

0 commit comments

Comments
 (0)