diff --git a/Content.Tests/DMProject/Tests/Builtins/world_error_infinite_loop.dm b/Content.Tests/DMProject/Tests/Builtins/world_error_infinite_loop.dm new file mode 100644 index 0000000000..306fcfa325 --- /dev/null +++ b/Content.Tests/DMProject/Tests/Builtins/world_error_infinite_loop.dm @@ -0,0 +1,19 @@ +//RUNTIME ERROR, RETURN TRUE +var/error_loop_count = 0 + +/world/Error() + error_loop_count++ + if(error_loop_count > 1) + world.log << "this is a test failure" + return + TestProc() + +/proc/SubError() + CRASH("we're doing an error!") + +/proc/TestProc() + SubError() + +/proc/RunTest() + TestProc() + return error_loop_count == 1 \ No newline at end of file diff --git a/OpenDreamRuntime/DreamManager.cs b/OpenDreamRuntime/DreamManager.cs index c58ebac292..753131ea2c 100644 --- a/OpenDreamRuntime/DreamManager.cs +++ b/OpenDreamRuntime/DreamManager.cs @@ -435,7 +435,7 @@ public ClientObjectReference GetClientReference(DreamObjectAtom atom) { } } - public void HandleException(Exception e, string msg = "", string file = "", int line = 0) { + public void HandleException(Exception e, string msg = "", string file = "", int line = 0, bool inWorldError = false) { if (string.IsNullOrEmpty(msg)) { // Just print the C# exception if we don't override the message msg = e.Message; } @@ -452,8 +452,12 @@ public void HandleException(Exception e, string msg = "", string file = "", int obj.Desc = new DreamValue(msg); obj.Line = new DreamValue(line); obj.File = new DreamValue(file); - - WorldInstance.SpawnProc("Error", usr: null, new DreamValue(obj)); + if (!inWorldError) // if an error occurs in /world/Error(), don't call it again + WorldInstance.SpawnProc("Error", usr: null, new DreamValue(obj)); + else { + _sawmill.Error("CRITICAL: An error occurred in /world/Error()"); + WriteWorldLog(msg); + } } public void OptionalException(WarningCode code, string exceptionText) where T : Exception { diff --git a/OpenDreamRuntime/DreamThread.cs b/OpenDreamRuntime/DreamThread.cs index a66dea78b4..625c7e4c0b 100644 --- a/OpenDreamRuntime/DreamThread.cs +++ b/OpenDreamRuntime/DreamThread.cs @@ -479,7 +479,14 @@ private void HandleException(Exception exception) { line = source.Item2; } - dreamMan.HandleException(exception, msg, file, line); + bool inWorldError = _current?.Proc?.OwningType == dreamMan.WorldInstance.ObjectDefinition.TreeEntry && _current.Proc.Name == "Error"; + if (!inWorldError && _stack.Count > 0) { + //if we're not directly in /world.Error, check the stack + var top = _stack.ElementAt(_stack.Count - 1); //only the top of the stack can be /world/Error + inWorldError = top.Proc?.OwningType == dreamMan.WorldInstance.ObjectDefinition.TreeEntry && top.Proc?.Name == "Error"; + } + + dreamMan.HandleException(exception, msg, file, line, inWorldError: inWorldError); IoCManager.Resolve().HandleException(this, exception); }