From 939e2ae27e9b803ef97e7b3d9da3385c0ac50e78 Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Sat, 31 Oct 2020 12:24:52 -0400 Subject: [PATCH 1/2] Added logic to direct lua script error messages to the output console window. Fixed crash issue described in issue #216. Crash was due to Qt GUI functions being used in the emulator thread. Only the main GUI thread is allowed to call Qt GUI functions. --- src/drivers/Qt/LuaControl.cpp | 71 ++++++++++++++++++++++++++++++++++- src/drivers/Qt/LuaControl.h | 13 +++++++ src/drivers/sdl/sdl.cpp | 37 ++++++++++++++++++ src/lua-engine.cpp | 39 +++++++++++++------ 4 files changed, 146 insertions(+), 14 deletions(-) diff --git a/src/drivers/Qt/LuaControl.cpp b/src/drivers/Qt/LuaControl.cpp index 87bddb56..338b5d55 100644 --- a/src/drivers/Qt/LuaControl.cpp +++ b/src/drivers/Qt/LuaControl.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../../fceu.h" @@ -23,6 +24,8 @@ static bool luaScriptRunning = false; static bool updateLuaDisplay = false; +static bool openLuaKillMsgBox = false; +static int luaKillMsgBoxRetVal = 0; struct luaConsoleOutputLine { @@ -215,6 +218,33 @@ void LuaControlDialog_t::updatePeriodic(void) updateLuaWindows(); updateLuaDisplay = false; } + + if ( openLuaKillMsgBox ) + { + openLuaKillMessageBox(); + openLuaKillMsgBox = false; + } +} +//---------------------------------------------------- +void LuaControlDialog_t::openLuaKillMessageBox(void) +{ + int ret; + QMessageBox msgBox(this); + + luaKillMsgBoxRetVal = 0; + + msgBox.setIcon( QMessageBox::Warning ); + msgBox.setText( tr("The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n") ); + msgBox.setStandardButtons(QMessageBox::Yes); + msgBox.addButton(QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + + ret = msgBox.exec(); + + if ( ret == QMessageBox::Yes ) + { + luaKillMsgBoxRetVal = 1; + } } //---------------------------------------------------- void LuaControlDialog_t::openLuaScriptFile(void) @@ -345,7 +375,7 @@ void WinLuaOnStart(intptr_t hDlgAsInt) //printf("Lua Script Running: %i \n", luaScriptRunning ); - updateLuaWindows(); + updateLuaDisplay = true; } //---------------------------------------------------- void WinLuaOnStop(intptr_t hDlgAsInt) @@ -354,7 +384,7 @@ void WinLuaOnStop(intptr_t hDlgAsInt) //printf("Lua Script Running: %i \n", luaScriptRunning ); - updateLuaWindows(); + updateLuaDisplay = true; } //---------------------------------------------------- void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str) @@ -366,3 +396,40 @@ void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str) updateLuaDisplay = true; } //---------------------------------------------------- +#ifdef WIN32 +int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char* const format, ...) +#else +int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw() +#endif +{ + int retval; + va_list args; + char msg[2048]; + va_start( args, format ); + retval = ::vsnprintf( msg, sizeof(msg), format, args ); + va_end(args); + + msg[ sizeof(msg)-1 ] = 0; + + outBuf.addLine( msg ); + + updateLuaDisplay = true; + + return(retval); +}; +//---------------------------------------------------- +int LuaKillMessageBox(void) +{ + //printf("Kill Lua Prompted\n"); + luaKillMsgBoxRetVal = 0; + + openLuaKillMsgBox = true; + + while ( openLuaKillMsgBox ) + { + usleep(100000); + } + + return luaKillMsgBoxRetVal; +} +//---------------------------------------------------- diff --git a/src/drivers/Qt/LuaControl.h b/src/drivers/Qt/LuaControl.h index fd475c17..a8fe50fe 100644 --- a/src/drivers/Qt/LuaControl.h +++ b/src/drivers/Qt/LuaControl.h @@ -30,6 +30,7 @@ class LuaControlDialog_t : public QDialog protected: void closeEvent(QCloseEvent *bar); + void openLuaKillMessageBox(void); QTimer *periodicTimer; QLineEdit *scriptPath; @@ -49,3 +50,15 @@ class LuaControlDialog_t : public QDialog void stopLuaScript(void); }; + +// Formatted print +#ifdef WIN32 + int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char* const format, ...) ; +#else + int LuaPrintfToWindowConsole(const char *__restrict format, ...) + __THROWNL __attribute__ ((__format__ (__printf__, 1, 2))); +#endif + +void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str); + +int LuaKillMessageBox(void); diff --git a/src/drivers/sdl/sdl.cpp b/src/drivers/sdl/sdl.cpp index 424dc53c..363c2d0f 100644 --- a/src/drivers/sdl/sdl.cpp +++ b/src/drivers/sdl/sdl.cpp @@ -1060,6 +1060,43 @@ void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str) printf("Lua Output: %s\n", str ); } //---------------------------------------------------- +int LuaKillMessageBox(void) +{ + int kill = 0; + fprintf(stderr, "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"); + char buffer[64]; + while (true) { + fprintf(stderr, "(y/n): "); + fgets(buffer, sizeof(buffer), stdin); + if (buffer[0] == 'y' || buffer[0] == 'Y') { + kill = 1; + break; + } + + if (buffer[0] == 'n' || buffer[0] == 'N') + break; + } + return 0; +} +//---------------------------------------------------- +#ifdef WIN32 +int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char* const format, ...) +#else +int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw() +#endif +{ + int retval; + va_list args; + char msg[2048]; + va_start( args, format ); + retval = ::vfprintf( stdout, format, args ); + va_end(args); + + msg[ sizeof(msg)-1 ] = 0; + + return(retval); +}; +//---------------------------------------------------- // dummy functions diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 3fb628c2..06c96dc2 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -188,6 +188,11 @@ static intptr_t info_uid; extern HWND LuaConsoleHWnd; extern INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); void TaseditorDisableManualFunctionIfNeeded(); + +#else +int LuaKillMessageBox(void); +int LuaPrintfToWindowConsole(const char *__restrict format, ...) + __THROWNL __attribute__ ((__format__ (__printf__, 1, 2))); #endif extern void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str); extern void WinLuaOnStart(intptr_t hDlgAsInt); @@ -1328,6 +1333,7 @@ void CallRegisteredLuaSaveFunctions(int savestateNumber, LuaSaveData& saveData) #ifdef WIN32 MessageBox(hAppWnd, lua_tostring(L, -1), "Lua Error in SAVE function", MB_OK); #else + LuaPrintfToWindowConsole("Lua error in registersave function: %s\n", lua_tostring(L, -1)); fprintf(stderr, "Lua error in registersave function: %s\n", lua_tostring(L, -1)); #endif } @@ -1380,6 +1386,7 @@ void CallRegisteredLuaLoadFunctions(int savestateNumber, const LuaSaveData& save #ifdef WIN32 MessageBox(hAppWnd, lua_tostring(L, -1), "Lua Error in LOAD function", MB_OK); #else + LuaPrintfToWindowConsole("Lua error in registerload function: %s\n", lua_tostring(L, -1)); fprintf(stderr, "Lua error in registerload function: %s\n", lua_tostring(L, -1)); #endif } @@ -2021,6 +2028,7 @@ void HandleCallbackError(lua_State* L) #ifdef WIN32 MessageBox( hAppWnd, errmsg, "Lua run error", MB_OK | MB_ICONSTOP); #else + LuaPrintfToWindowConsole("Lua thread bombed out: %s\n", errmsg); fprintf(stderr, "Lua thread bombed out: %s\n", errmsg); #endif @@ -5729,19 +5737,23 @@ static void FCEU_LuaHookFunction(lua_State *L, lua_Debug *dbg) { } #else - fprintf(stderr, "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"); - char buffer[64]; - while (TRUE) { - fprintf(stderr, "(y/n): "); - fgets(buffer, sizeof(buffer), stdin); - if (buffer[0] == 'y' || buffer[0] == 'Y') { - kill = 1; - break; - } - - if (buffer[0] == 'n' || buffer[0] == 'N') - break; + if ( LuaKillMessageBox() ) + { + kill = 1; } + //fprintf(stderr, "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"); + //char buffer[64]; + //while (TRUE) { + // fprintf(stderr, "(y/n): "); + // fgets(buffer, sizeof(buffer), stdin); + // if (buffer[0] == 'y' || buffer[0] == 'Y') { + // kill = 1; + // break; + // } + + // if (buffer[0] == 'n' || buffer[0] == 'N') + // break; + //} #endif if (kill) { @@ -6138,6 +6150,7 @@ void FCEU_LuaFrameBoundary() //StopSound();//StopSound(); //mbg merge 7/23/08 MessageBox( hAppWnd, errmsg, "Lua run error", MB_OK | MB_ICONSTOP); #else + LuaPrintfToWindowConsole("Lua thread bombed out: %s\n", errmsg); fprintf(stderr, "Lua thread bombed out: %s\n", errmsg); #endif } else { @@ -6279,6 +6292,7 @@ int FCEU_LoadLuaCode(const char *filename, const char *arg) { //StopSound();//StopSound(); //mbg merge 7/23/08 MessageBox(NULL, lua_tostring(L,-1), "Lua load error", MB_OK | MB_ICONSTOP); #else + LuaPrintfToWindowConsole("Failed to compile file: %s\n", lua_tostring(L,-1)); fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(L,-1)); #endif @@ -6497,6 +6511,7 @@ void FCEU_LuaGui(uint8 *XBuf) //StopSound();//StopSound(); //mbg merge 7/23/08 MessageBox(hAppWnd, lua_tostring(L, -1), "Lua Error in GUI function", MB_OK); #else + LuaPrintfToWindowConsole("Lua error in gui.register function: %s\n", lua_tostring(L, -1)); fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(L, -1)); #endif // This is grounds for trashing the function From 5d6cda446ab8ecf77fd38e54ce4be88884b6b735 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Sat, 31 Oct 2020 12:40:31 -0400 Subject: [PATCH 2/2] Compile fix for macOS. --- src/drivers/Qt/LuaControl.h | 4 +++- src/lua-engine.cpp | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/drivers/Qt/LuaControl.h b/src/drivers/Qt/LuaControl.h index a8fe50fe..811346a6 100644 --- a/src/drivers/Qt/LuaControl.h +++ b/src/drivers/Qt/LuaControl.h @@ -54,9 +54,11 @@ class LuaControlDialog_t : public QDialog // Formatted print #ifdef WIN32 int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char* const format, ...) ; -#else +#elif __linux__ int LuaPrintfToWindowConsole(const char *__restrict format, ...) __THROWNL __attribute__ ((__format__ (__printf__, 1, 2))); +#else + int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw(); #endif void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str); diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 06c96dc2..2e7d21c2 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -191,8 +191,13 @@ void TaseditorDisableManualFunctionIfNeeded(); #else int LuaKillMessageBox(void); +#ifdef __linux__ int LuaPrintfToWindowConsole(const char *__restrict format, ...) __THROWNL __attribute__ ((__format__ (__printf__, 1, 2))); +#else +int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw(); +#endif + #endif extern void PrintToWindowConsole(intptr_t hDlgAsInt, const char* str); extern void WinLuaOnStart(intptr_t hDlgAsInt);