From a6a8173e205f97afee0a40f2d47de4e9c623460e Mon Sep 17 00:00:00 2001 From: Misa Date: Mon, 7 Sep 2020 20:58:32 -0700 Subject: [PATCH] Prevent same-frame infinite loops in scripts It's trivially easy to send the scripting system into an infinite loop on the same frame (i.e. without any script delay in between, i.e. within the same execution of script.run()). Just take a look at these two scripts: a: iftrinkets(0,b) # b: iftrinkets(0,a) # The hashes are to prevent the scripting system from parsing iftrinkets() using the internal version instead of the simplified version, because after doing a simplified iftrinkets(), the parser will (to oversimplify) execute the last line of the script as internal. Anyway, sending the game into an infinite loop like this will cause the Not Responding dialog on Windows. So to prevent this from happening, I've added an execution counter to scriptclass::run(). If it gets too high, we're in an infinite loop and so we stop running the script. --- desktop_version/src/Script.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index 49f9969e..e98f2e03 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -9,6 +9,8 @@ #include "Music.h" #include "UtilityClass.h" +#include + scriptclass::scriptclass() { //Start SDL @@ -76,6 +78,8 @@ void scriptclass::tokenize( const std::string& t ) void scriptclass::run() { + // This counter here will stop the function when it gets too high + short execution_counter = 0; while(running && scriptdelay<=0 && !game.pausescript) { if (position < (int) commands.size()) @@ -2603,6 +2607,17 @@ void scriptclass::run() { running = false; } + // Don't increment if we're at the max, signed int overflow is UB + if (execution_counter == SHRT_MAX) + { + // We must be in an infinite loop + printf("Warning: execution counter got to %i, stopping script\n", SHRT_MAX); + running = false; + } + else + { + execution_counter++; + } } if(scriptdelay>0)