|
26 | 26 | package com.oracle.graal.python.builtins.objects.traceback;
|
27 | 27 |
|
28 | 28 | import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
|
| 29 | +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError; |
29 | 30 | import static com.oracle.graal.python.builtins.objects.traceback.PTraceback.TB_FRAME;
|
30 | 31 | import static com.oracle.graal.python.builtins.objects.traceback.PTraceback.TB_LASTI;
|
31 | 32 | import static com.oracle.graal.python.builtins.objects.traceback.PTraceback.TB_LINENO;
|
|
58 | 59 | import com.oracle.truffle.api.frame.VirtualFrame;
|
59 | 60 | import com.oracle.truffle.api.nodes.Node;
|
60 | 61 | import com.oracle.truffle.api.profiles.ConditionProfile;
|
| 62 | +import com.oracle.truffle.api.profiles.LoopConditionProfile; |
61 | 63 | import com.oracle.truffle.api.source.SourceSection;
|
62 | 64 |
|
63 | 65 | @CoreFunctions(extendClasses = PythonBuiltinClassType.PTraceback)
|
@@ -271,7 +273,16 @@ Object get(PTraceback self, @SuppressWarnings("unused") PNone none,
|
271 | 273 |
|
272 | 274 | @Specialization(guards = "!isNoValue(next)")
|
273 | 275 | Object set(PTraceback self, PTraceback next,
|
| 276 | + @Cached("createCountingProfile()") LoopConditionProfile loopProfile, |
274 | 277 | @Cached MaterializeTruffleStacktraceNode materializeTruffleStacktraceNode) {
|
| 278 | + // Check for loops |
| 279 | + PTraceback tb = next; |
| 280 | + while (loopProfile.profile(tb != null)) { |
| 281 | + if (tb == self) { |
| 282 | + throw raise(ValueError, "traceback loop detected"); |
| 283 | + } |
| 284 | + tb = tb.getNext(); |
| 285 | + } |
275 | 286 | // Realize whatever was in the truffle stacktrace, so that we don't overwrite the
|
276 | 287 | // user-set next later
|
277 | 288 | materializeTruffleStacktraceNode.execute(self);
|
|
0 commit comments