Skip to content

Commit be80db1

Browse files
authored
pythonGH-94438: Account for NULLs on evaluation stack when jumping lines. (pythonGH-94444)
1 parent 0228002 commit be80db1

File tree

3 files changed

+106
-17
lines changed

3 files changed

+106
-17
lines changed

Lib/test/test_sys_settrace.py

Lines changed: 61 additions & 4 deletions
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 43 additions & 13 deletions
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,31 @@ 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+
{
322+
int j = get_arg(code, i);
323+
if (j & 1) {
324+
next_stack = push_value(next_stack, Null);
325+
}
326+
next_stack = push_value(next_stack, Object);
327+
stacks[i+1] = next_stack;
328+
break;
329+
}
330+
case LOAD_ATTR:
331+
{
332+
int j = get_arg(code, i);
333+
if (j & 1) {
334+
next_stack = pop_value(next_stack);
335+
next_stack = push_value(next_stack, Null);
336+
next_stack = push_value(next_stack, Object);
337+
}
338+
stacks[i+1] = next_stack;
339+
break;
340+
}
301341
default:
302342
{
303343
int delta = PyCompile_OpcodeStackEffect(opcode, _Py_OPARG(code[i]));
@@ -318,17 +358,6 @@ mark_stacks(PyCodeObject *code_obj, int len)
318358
return stacks;
319359
}
320360

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-
332361
static int
333362
compatible_stack(int64_t from_stack, int64_t to_stack)
334363
{
@@ -365,7 +394,8 @@ explain_incompatible_stack(int64_t to_stack)
365394
case Except:
366395
return "can't jump into an 'except' block as there's no exception";
367396
case Object:
368-
return "differing stack depth";
397+
case Null:
398+
return "incompatible stacks";
369399
case Iterator:
370400
return "can't jump into the body of a for loop";
371401
default:

0 commit comments

Comments
 (0)