Skip to content

Commit ad0dc04

Browse files
committed
Prevent tb_next loop
1 parent e79a1a1 commit ad0dc04

2 files changed

Lines changed: 22 additions & 5 deletions

File tree

Lib/test/test_raise.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,6 @@ class TestTracebackType(unittest.TestCase):
244244
def raiser(self):
245245
raise ValueError
246246

247-
@unittest.expectedFailure # TODO: RUSTPYTHON
248247
def test_attrs(self):
249248
try:
250249
self.raiser()

crates/vm/src/builtins/traceback.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::PyType;
22
use crate::{
3-
Context, Py, PyPayload, PyRef, PyResult, VirtualMachine, class::PyClassImpl, frame::FrameRef,
4-
types::Constructor,
3+
AsObject, Context, Py, PyPayload, PyRef, PyResult, VirtualMachine, class::PyClassImpl,
4+
frame::FrameRef, types::Constructor,
55
};
66
use rustpython_common::lock::PyMutex;
77
use rustpython_compiler_core::OneIndexed;
@@ -63,8 +63,26 @@ impl PyTraceback {
6363
}
6464

6565
#[pygetset(setter)]
66-
fn set_tb_next(&self, value: Option<PyRef<Self>>) {
67-
*self.next.lock() = value;
66+
fn set_tb_next(
67+
zelf: &Py<Self>,
68+
value: Option<PyRef<Self>>,
69+
vm: &VirtualMachine,
70+
) -> PyResult<()> {
71+
if let Some(ref new_next) = value {
72+
let mut cursor = new_next.clone();
73+
loop {
74+
if cursor.is(zelf) {
75+
return Err(vm.new_value_error("traceback loop detected".to_owned()));
76+
}
77+
let next = cursor.next.lock().clone();
78+
match next {
79+
Some(n) => cursor = n,
80+
None => break,
81+
}
82+
}
83+
}
84+
*zelf.next.lock() = value;
85+
Ok(())
6886
}
6987
}
7088

0 commit comments

Comments
 (0)