mudlet/src/LuaInterface.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

862 lines
32 KiB
C++
Raw Normal View History

/***************************************************************************
* Copyright (C) 2013 by Chris Mitchell *
* Copyright (C) 2014 by Ahmed Charles - acharles@outlook.com *
* Copyright (C) 2020, 2023 by Stephen Lyons - slysven@virginmedia.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QDebug>
#include "LuaInterface.h"
#include "VarUnit.h"
#include "utils.h"
#include <csetjmp>
extern "C" {
Fix: ensure we include the right Lua header files (#7842) #### Brief overview of PR changes/additions For Windows builds modify the `#include` lines for Lua header files to specify the 5.1 version. Also accommodate some changes in our CI build environment: * For some reason (maybe because of a more modern linker) we need to specify the original PCRE library with `-lpcre` rather than `-lpcre-1` - the exact cause of this is not clear but thanks to @jmckisson for finding it (and using it in his attempt to solve the same problems this PR is doing). * It seems the Window building is now being done in the `C:` drive rather than the previous `D:` one, so a tweak to clean the colon containing file-system root specifier to the alternative that MSYS2+Mingw-w64 uses which instead uses a (POSIX) `/` root directory followed by a single lower-case letter to specify the drive needs to be extended to handle both drives. This is because the scripts use `rsync` and that treats any `:` as the separator between host and path and gets confused when it sees a "Windows" path containing it! #### Motivation for adding to Mudlet The default version - and the one needed for some packages like Luarocks is a 5.4 one - and that includes header files in the "default" `include` directory. So the headers that get pulled in are the wrong ones, which fail to work as they are not compatible with Lua 5.1; to get the 5.1 instead I believe we need to explicitly include the version specific sub-directory in the `#include` lines. Other tweaks are also needed "to get things working nowadays." #### Other info (issues closed, discussion etc) This should be simpler to do than what is being attempted by #7841. --------- Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2025-05-17 22:34:05 +01:00
#if defined(INCLUDE_VERSIONED_LUA_HEADERS)
#include <lua5.1/lauxlib.h>
#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#else
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#endif
}
static jmp_buf buf;
LuaInterface::LuaInterface(lua_State* L)
: mL(L)
{
2014-09-29 04:08:18 -07:00
varUnit.reset(new VarUnit());
//set our panic function
lua_atpanic(L, &onPanic);
}
fix: two ways a profile save could lose or resurrect your data (#9704) #### Brief overview of PR changes/additions - Variables: the export skipped its refresh whenever the editor's Variables view was on screen, so anything a script wrote into a saved variable while it sat open was dropped from the save - including the session's last save, which is taken with whatever view the editor was left on. The variables are now read into a throwaway tree, which also stops a save stranding the editor's variable search results. - Packages: a save taken while a unit was still executing an item of a package that had just been uninstalled wrote that package's items back into the profile, where they returned as orphans the Package Manager could not remove. The XML writers now skip what the units have queued for a deferred delete, the module writer included - reloading a module from a script used to write both the pre- and post-reload copies of its items into the module file. - `LuaInterface::getVars()` is now `setjmp`-guarded like every other Lua-touching method there, so a panic cannot jump past the export's scope with its variable tree and registry references still held. #### Motivation for adding to Mudlet Both are silent data loss in everyday use: quitting with the editor on the Variables tab, and the `mpkg`/auto-updater shape of uninstalling a package from a script. #### Other info (issues closed, discussion etc) From the 5.0 QA sweep, findings C13 and C14. The variables half re-opens the loss that `20009c5ec` "fix: variables added while playing are no longer lost when saving (#9492)" fixed, via the guard it added; the packages half is the missing counterpart to the self-uninstall deferral in `276e8bbfd` (#9383) and its follow-ups. #9492's own cases still pass unchanged. **Test case:** create a table from the command line, tick it to be saved in the editor's Variables view, leave the editor there, run `lua myTable.later = "x"`, quit and reopen - `later` is still there. `ctest -R 'XMLexportVariablesTest|PackageSelfUninstallTest'` covers both halves; all 12 new cases were verified to fail against the unfixed source. Assisted-by: Claude:claude-opus-5
2026-08-07 10:14:45 +02:00
// Does not release lrefs: a profile reset closes the lua_State before this
// object is replaced, so unref'ing here would write into a freed state.
LuaInterface::~LuaInterface() = default;
2014-09-29 04:08:18 -07:00
2017-04-27 03:55:38 -07:00
int LuaInterface::onPanic(lua_State* L)
{
QString error = "Lua Panic, No error information";
2017-04-27 03:55:38 -07:00
if (lua_isstring(L, -1)) {
error = lua_tostring(L, -1);
qDebug() << "Lua panic:" << error;
}
longjmp(buf, 1);
return 1;
}
2017-04-27 03:55:38 -07:00
VarUnit* LuaInterface::getVarUnit()
{
2014-09-29 04:08:18 -07:00
return varUnit.data();
}
fix: two ways a profile save could lose or resurrect your data (#9704) #### Brief overview of PR changes/additions - Variables: the export skipped its refresh whenever the editor's Variables view was on screen, so anything a script wrote into a saved variable while it sat open was dropped from the save - including the session's last save, which is taken with whatever view the editor was left on. The variables are now read into a throwaway tree, which also stops a save stranding the editor's variable search results. - Packages: a save taken while a unit was still executing an item of a package that had just been uninstalled wrote that package's items back into the profile, where they returned as orphans the Package Manager could not remove. The XML writers now skip what the units have queued for a deferred delete, the module writer included - reloading a module from a script used to write both the pre- and post-reload copies of its items into the module file. - `LuaInterface::getVars()` is now `setjmp`-guarded like every other Lua-touching method there, so a panic cannot jump past the export's scope with its variable tree and registry references still held. #### Motivation for adding to Mudlet Both are silent data loss in everyday use: quitting with the editor on the Variables tab, and the `mpkg`/auto-updater shape of uninstalling a package from a script. #### Other info (issues closed, discussion etc) From the 5.0 QA sweep, findings C13 and C14. The variables half re-opens the loss that `20009c5ec` "fix: variables added while playing are no longer lost when saving (#9492)" fixed, via the guard it added; the packages half is the missing counterpart to the self-uninstall deferral in `276e8bbfd` (#9383) and its follow-ups. #9492's own cases still pass unchanged. **Test case:** create a table from the command line, tick it to be saved in the editor's Variables view, leave the editor there, run `lua myTable.later = "x"`, quit and reopen - `later` is still there. `ctest -R 'XMLexportVariablesTest|PackageSelfUninstallTest'` covers both halves; all 12 new cases were verified to fail against the unfixed source. Assisted-by: Claude:claude-opus-5
2026-08-07 10:14:45 +02:00
lua_State* LuaInterface::getState() const
{
return mL;
}
void LuaInterface::releaseVariableReferences()
{
for (const int ref : std::as_const(lrefs)) {
luaL_unref(mL, LUA_REGISTRYINDEX, ref);
}
lrefs.clear();
}
2017-04-27 03:55:38 -07:00
QStringList LuaInterface::varName(TVar* var)
{
QStringList names;
if (var->getName() == qsl("_G")) {
names << "";
return names;
}
names << var->getName();
TVar* pParent = var->getParent();
while (pParent && pParent->getName() != qsl("_G")) {
names.insert(0, pParent->getName());
pParent = pParent->getParent();
}
return names;
}
std::pair<bool, QString> LuaInterface::validMove(QTreeWidgetItem* pWidget)
2017-04-27 03:55:38 -07:00
{
TVar* pNewParent = varUnit->getWVar(pWidget);
if (pNewParent && pNewParent->getValueType() != LUA_TTABLE) {
//: Error message shown when user tries to drag a variable onto a non-table variable
return {false, QObject::tr("Cannot move variable here - the target is not a table")};
}
return {true, QString()};
}
2017-04-27 03:55:38 -07:00
void LuaInterface::getAllChildren(TVar* var, QList<TVar*>* list)
{
QListIterator<TVar*> it(var->getChildren(true));
if (varUnit->isSaved(var) || var->saved) {
list->append(var);
}
2017-04-27 03:55:38 -07:00
while (it.hasNext()) {
TVar* child = it.next();
if (child->getValueType() == LUA_TTABLE) {
2017-04-27 03:55:38 -07:00
getAllChildren(child, list);
} else if (varUnit->isSaved(child) || var->saved) {
list->append(child);
}
}
}
2017-04-27 03:55:38 -07:00
bool LuaInterface::loadKey(lua_State* L, TVar* var)
{
if (setjmp(buf) == 0) {
const int keyType = var->getKeyType();
2017-04-27 03:55:38 -07:00
if (var->isReference()) {
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
if (keyType == LUA_TNUMBER) {
lua_pushnumber(L, var->getName().toDouble());
} else if (keyType == LUA_TTABLE) {
} else if (keyType == LUA_TBOOLEAN) {
2017-04-27 03:55:38 -07:00
lua_pushboolean(L, var->getName().toLower() == "true" ? 1 : 0);
} else {
lua_pushstring(L, var->getName().toUtf8().constData());
}
}
return lua_type(L, -1) == keyType;
}
return false;
}
2017-04-27 03:55:38 -07:00
bool LuaInterface::loadValue(lua_State* L, TVar* var, int index)
{
//puts a value on stack
2017-04-27 03:55:38 -07:00
if (setjmp(buf) == 0) {
if (loadKey(L, var)) {
//everything is tabled in lua, we need to just find what table
//we're using, if index == 0, we iterate to the closest table
if (index) {
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
// Validate stack before attempting table access
const int stackTop = lua_gettop(L);
const int actualIndex = (index < 0) ? stackTop + index + 1 : index;
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
if (actualIndex <= 0 || actualIndex > stackTop) {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::loadValue() - Invalid stack index " << index << " for variable \"" << var->getName() << "\". Stack size: " << stackTop
<< ", resolved index: " << actualIndex << ".";
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
return false;
}
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
if (!lua_istable(L, index)) {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::loadValue() - Value at stack index " << index << " is not a table for variable \"" << var->getName()
<< "\". Got type: " << lua_typename(L, lua_type(L, index)) << ".";
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
return false;
}
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
lua_gettable(L, index);
} else {
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
// Find the closest table on the stack
bool foundTable = false;
2017-04-27 03:55:38 -07:00
for (int j = 1; j <= lua_gettop(L); j++) {
if (lua_type(L, j * -1) == LUA_TTABLE) {
lua_gettable(L, j * -1);
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
foundTable = true;
break;
}
}
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
if (!foundTable) {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::loadValue() - No table found on stack for variable \"" << var->getName() << "\" when index=0. Stack size: " << lua_gettop(L)
<< ".";
Fix: Comprehensive package installation crash prevention (#8541) ## Brief overview of PR changes/additions Comprehensive fix for package installation crashes (issue #8154) that builds upon the defensive checks from @vadi2's PR #8181. This PR addresses the root causes of the crash by: 1. **Blocking concurrent operations** - Prevents package installation while profile save is in progress 2. **Deferring event handlers** - Moves sysInstall event raising to after package import completes 3. **Improving error recovery** - Better validation in LuaInterface when searching for Lua tables ## Motivation for adding to Mudlet Fixes #8154 - crash when installing packages with variables in certain profiles The crash occurred because: - Variables were being loaded into Lua state while event handlers were executing - Profile save and package installation could run concurrently - Event handlers triggered during XMLimport could corrupt Lua stack state ## Other info This PR incorporates and builds upon @vadi2's excellent diagnostic work in PR #8181. The defensive checks from that PR are included, plus additional fixes for the underlying race conditions. **Changes in this PR:** ### From vadi2's PR #8181: - Added Lua stack validation in `LuaInterface::loadValue()` before calling `lua_gettable()` - Added null check for Lua state in `callEventHandler()` - Fixed stack index bug (using `-1` instead of `1` for error checking) - Added stack cleanup on error paths - Added emergency stop mode check ### Additional fixes in this PR: - Added `currentlySavingProfile()` check at the start of `Host::installPackage()` to prevent concurrent operations - Deferred `sysInstall`, `sysInstallPackage`, and related event handlers to execute after package import completes using `QTimer::singleShot()` - Added validation and error reporting when searching for tables with `index=0` in `LuaInterface::loadValue()` Co-authored-by: @vadi2 --------- Co-authored-by: Vadim Peretokin <vadi2@users.noreply.github.com> Co-authored-by: Vadim Peretokin <vperetokin@hey.com>
2025-11-18 03:49:49 -05:00
return false;
}
}
2017-04-27 03:55:38 -07:00
} else {
return false;
2017-04-27 03:55:38 -07:00
}
if (lua_gettop(L)) {
return lua_type(L, -1) == var->getValueType();
2017-04-27 03:55:38 -07:00
}
return false;
}
return false;
}
2017-04-27 03:55:38 -07:00
bool LuaInterface::reparentCVariable(TVar* from, TVar* to, TVar* curVar)
{
//get the old parent on the stack
2017-04-27 03:55:38 -07:00
if (setjmp(buf) == 0) {
if (!from || !to || (from == to)) {
// moving from global to global or nowhere
return true;
2017-04-27 03:55:38 -07:00
}
const int stackSize = lua_gettop(mL);
const bool isSaved = varUnit->isSaved(curVar);
2017-04-27 03:55:38 -07:00
if (isSaved) {
QList<TVar*> list;
getAllChildren(curVar, &list);
2017-04-27 03:55:38 -07:00
QListIterator<TVar*> it(list);
while (it.hasNext()) {
TVar* t = it.next();
varUnit->removeSavedVar(t);
}
}
2017-04-27 03:55:38 -07:00
QList<TVar*> vars = varOrder(curVar);
lua_getglobal(mL, (vars[0]->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
int i = 1;
for (; i < vars.size(); i++) {
if (!loadValue(mL, vars[i], -2)) {
lua_settop(mL, stackSize);
return false;
}
}
//redo the parenting in TVar
from->removeChild(curVar);
curVar->setParent(to);
to->addChild(curVar);
vars = varOrder(curVar);
//do the actual reparenting part
2017-04-27 03:55:38 -07:00
if (to == varUnit->getBase()) {
//we're going global
lua_setglobal(mL, curVar->getName().toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else {
lua_getglobal(mL, (vars[0]->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
i = 1;
for (; i < vars.size() - 1; i++) {
if (!loadValue(mL, vars[i], -2)) {
lua_settop(mL, stackSize);
return false;
}
lua_remove(mL, -2);
}
lua_insert(mL, -2);
if (!loadKey(mL, curVar)) {
lua_settop(mL, stackSize);
return false;
}
lua_insert(mL, -2);
if (!lua_istable(mL, -3)) {
lua_settop(mL, stackSize);
return false;
}
lua_settable(mL, -3);
lua_pop(mL, 1);
}
//delete the old copy
2017-04-27 03:55:38 -07:00
if (from == varUnit->getBase()) {
lua_pushnil(mL);
lua_setglobal(mL, curVar->getName().toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else {
if (!loadKey(mL, curVar)) {
lua_settop(mL, stackSize);
return false;
}
lua_pushnil(mL);
if (!lua_istable(mL, -3)) {
lua_settop(mL, stackSize);
return false;
}
lua_settable(mL, -3);
}
2017-04-27 03:55:38 -07:00
if (isSaved) {
QList<TVar*> list;
list.append(to);
getAllChildren(curVar, &list);
2017-04-27 03:55:38 -07:00
QListIterator<TVar*> it(list);
while (it.hasNext()) {
TVar* t = it.next();
varUnit->addSavedVar(t);
}
}
lua_settop(mL, stackSize);
return true;
}
2014-01-10 21:41:20 -05:00
return false;
}
2017-04-27 03:55:38 -07:00
bool LuaInterface::reparentVariable(QTreeWidgetItem* newP, QTreeWidgetItem* cItem, QTreeWidgetItem* oldP)
{
//if oldParent doesn't exist:
//this means we were moved to a table from the global namespace
//if newParent doesn't exist:
//we were moved to the global namespace
//if both exist:
//this means we were moved from inside a table to inside another table
//and in both instances, this table was not _G
TVar* curVar = varUnit->getWVar(cItem);
if (!curVar) {
return false;
}
2017-04-27 03:55:38 -07:00
TVar* newParent = varUnit->getWVar(newP);
TVar* oldParent = varUnit->getWVar(oldP);
TVar* from = oldParent;
TVar* to = newParent;
if (newParent && newParent->getValueType() != LUA_TTABLE) {
2014-01-10 21:41:20 -05:00
//FIXME: report why this fails to user
return false;
}
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
2017-04-27 03:55:38 -07:00
if (!newParent && !oldParent) {
//happens when we move from _G to _G
return false;
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
}
if (!oldParent) {
from = varUnit->getBase();
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
// newParent cannot be a nullptr here as we would have returned in
// previous if - so to won't be either:
to = newParent;
2017-04-27 03:55:38 -07:00
} else if (!newParent) {
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
// oldParent cannot be a nullptr here as we would have returned in
// previous if - so from won't be either:
from = oldParent;
to = varUnit->getBase();
}
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
// one of from and to must not be a nullptr here - so prior test for BOTH
// being a nullptr here and returning false in that case was dead code.
2017-04-27 03:55:38 -07:00
return reparentCVariable(from, to, curVar);
}
2017-04-27 03:55:38 -07:00
QList<TVar*> LuaInterface::varOrder(TVar* var)
{
QList<TVar*> vars;
if (var->getName() == qsl("_G")) {
return vars;
}
vars << var;
TVar* pParent = var->getParent();
while (pParent && pParent->getName() != qsl("_G")) {
vars.insert(0, pParent);
pParent = pParent->getParent();
}
return vars;
}
2017-04-27 03:55:38 -07:00
void LuaInterface::createVar(TVar* var)
{
setValue(var);
}
2017-04-27 03:55:38 -07:00
bool LuaInterface::setCValue(QList<TVar*> vars)
{
//make the new stack
2017-04-27 03:55:38 -07:00
TVar* var = vars.back();
if (setjmp(buf) == 0) {
const int stackSize = lua_gettop(mL);
lua_getglobal(mL, (vars[0]->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
int i = 1;
for (; i < vars.size() - 1; i++) {
if (!loadValue(mL, vars[i], -2)) {
lua_settop(mL, stackSize);
return false;
}
}
//push our value onto the stack
2017-04-27 03:55:38 -07:00
switch (var->getValueType()) {
case LUA_TSTRING:
lua_pushstring(mL, var->getValue().toUtf8().constData());
break;
case LUA_TNUMBER:
lua_pushnumber(mL, var->getValue().toDouble());
break;
case LUA_TBOOLEAN:
lua_pushboolean(mL, var->getValue().toLower() == "true" ? 1 : 0);
break;
case LUA_TTABLE:
lua_newtable(mL);
break;
default:
lua_settop(mL, stackSize);
return false;
}
//set it up
if (lua_type(mL, -1) != var->getValueType()) {
lua_settop(mL, stackSize);
return false;
}
lua_settable(mL, -3);
}
2014-01-10 21:41:20 -05:00
return false;
}
// sets the value of a Lua variable by running dynamically-generated Lua code
2017-04-27 03:55:38 -07:00
bool LuaInterface::setValue(TVar* var)
{
//This function assumes the var has been modified and then called
2017-04-27 03:55:38 -07:00
QList<TVar*> vars = varOrder(var);
QString variableChangeCode = vars[0]->getName();
2017-04-27 03:55:38 -07:00
for (int i = 1; i < vars.size(); i++) {
if (vars[i]->isReference()) {
2017-04-27 03:55:38 -07:00
return setCValue(vars);
}
const int keyType = vars[i]->getKeyType();
if (keyType == LUA_TNUMBER || keyType == LUA_TBOOLEAN) {
variableChangeCode.append(qsl("[%1]").arg(vars.at(i)->getName()));
2017-04-27 03:55:38 -07:00
} else {
variableChangeCode.append(qsl(R"(["%1"])").arg(vars.at(i)->getName()));
}
}
2017-04-27 03:55:38 -07:00
switch (var->getValueType()) {
case LUA_TSTRING:
variableChangeCode.append(qsl(" = [[%1]]").arg(var->getValue()));
break;
case LUA_TNUMBER:
variableChangeCode.append(qsl(" = %1").arg(var->getValue()));
break;
case LUA_TBOOLEAN:
variableChangeCode.append(qsl(" = %1").arg(var->getValue()));
break;
case LUA_TTABLE:
variableChangeCode.append(QLatin1String(" = {}"));
break;
default:
return false;
}
int error = luaL_loadstring(mL, variableChangeCode.toUtf8().constData());
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
if (error) {
qWarning().noquote().nospace() << "LuaInterface::setValue(...) WARNING - Internal Lua (parsing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\"" << variableChangeCode << "\".";
return false;
}
error = lua_pcall(mL, 0, LUA_MULTRET, 0);
2017-04-27 03:55:38 -07:00
if (error) {
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
qWarning().noquote().nospace() << "LuaInterface::setValue(...) WARNING - Internal Lua (executing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\"" << variableChangeCode << "\".";
return false;
}
return true;
}
2017-04-27 03:55:38 -07:00
void LuaInterface::deleteVar(TVar* var)
{
QList<TVar*> vars = varOrder(var);
QString oldName = vars[0]->getName();
2017-04-27 03:55:38 -07:00
for (int i = 1; i < vars.size(); i++) {
const int keyType = vars[i]->getKeyType();
if (keyType == LUA_TNUMBER || keyType == LUA_TBOOLEAN) {
oldName.append(qsl("[%1]").arg(vars[i]->getName()));
2017-04-27 03:55:38 -07:00
} else {
oldName.append(qsl(R"(["%1"])").arg(vars[i]->getName()));
}
}
//delete it
oldName.append(qsl(" = nil"));
int error = luaL_loadstring(mL, oldName.toUtf8().constData());
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
if (error) {
qWarning().noquote().nospace() << "LuaInterface::deleteVar(...) WARNING - Internal Lua (parsing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\"" << oldName << "\".";
return;
}
error = lua_pcall(mL, 0, LUA_MULTRET, 0);
2017-04-27 03:55:38 -07:00
if (error) {
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
qWarning().noquote().nospace() << "LuaInterface::deleteVar(...) WARNING - Internal Lua (executing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\"" << oldName << "\".";
}
}
2017-04-27 03:55:38 -07:00
void LuaInterface::renameCVar(QList<TVar*> vars)
{
//uses C Api to rename a variable.
//dangerous function since you can get an api panic
//and trash the stack
2017-04-27 03:55:38 -07:00
TVar* var = vars.back();
//make the new stack
lua_getglobal(mL, (vars[0]->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
if (setjmp(buf) == 0) {
int i = 1;
int pushCount = 0;
int kType;
2017-04-27 03:55:38 -07:00
for (; i < vars.size() - 1; i++) {
kType = vars[i]->getKeyType();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, QString(vars[i]->getName()).toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE) {
// registry references are integer refs so must stay toInt()
lua_rawgeti(mL, LUA_REGISTRYINDEX, vars[i]->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
lua_pushstring(mL, QString(vars[i]->getName()).toUtf8().constData());
}
lua_gettable(mL, -2);
if (lua_isnil(mL, -1)) {
//value didn't exist, make it
lua_pop(mL, -1);
2017-04-27 03:55:38 -07:00
if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, QString(vars[i]->getName()).toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE || kType == LUA_TFUNCTION) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, vars[i]->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
lua_pushstring(mL, QString(vars[i]->getName()).toUtf8().constData());
}
lua_newtable(mL);
lua_settable(mL, -3);
2017-04-27 03:55:38 -07:00
i--; //decrement since we want to reput this table on the stack on next iteration
}
}
kType = var->getKeyType();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TSTRING) {
lua_pushstring(mL, QString(var->getNewName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, var->getNewName().toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, var->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::renameCVar() - Unsupported key type: " << lua_typename(mL, kType) << " for variable \"" << var->getName()
<< "\". Expected string, number, or table.";
return;
}
//put the old value on the stack
lua_getglobal(mL, (vars[0]->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
i = 1;
for (; i < vars.size() - 1; i++) {
kType = vars[i]->getKeyType();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, QString(vars[i]->getName()).toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE || kType == LUA_TFUNCTION) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, vars[i]->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
lua_pushstring(mL, QString(vars[i]->getName()).toUtf8().constData());
}
lua_gettable(mL, -2);
pushCount++;
}
kType = var->getKeyType();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TSTRING) {
lua_pushstring(mL, QString(var->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, var->getName().toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE || kType == LUA_TFUNCTION) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, var->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::renameCVar() - Unsupported key type when retrieving old value: " << lua_typename(mL, kType) << " for variable \"" << var->getName()
<< "\". Expected string, number, table, or function.";
return;
}
lua_gettable(mL, -2);
pushCount++;
//old value is @ -1 now
//we want to put our new named key @ -2
kType = var->getKeyType();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TSTRING) {
lua_pushstring(mL, QString(var->getNewName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, var->getNewName().toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, var->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::renameCVar() - Unsupported key type when setting new key: " << lua_typename(mL, kType) << " for variable \"" << var->getName()
<< "\". Expected string, number, or table.";
return;
}
pushCount++;
lua_insert(mL, -2);
lua_settable(mL, -3 - pushCount);
//key & value popped
//delete it, so we put the old key back on the stack and set to nil
kType = var->getKeyType();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TSTRING) {
lua_pushstring(mL, QString(var->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, var->getName().toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE || kType == LUA_TFUNCTION) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, var->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::renameCVar() - Unsupported key type when deleting old key: " << lua_typename(mL, kType) << " for variable \"" << var->getName()
<< "\". Expected string, number, table, or function.";
return;
}
lua_pushnil(mL);
lua_settable(mL, -3);
var->clearNewName();
}
}
2017-04-27 03:55:38 -07:00
bool LuaInterface::loadVar(TVar* var)
{
//puts the value of a variable on the -1 position of the stack
2017-04-27 03:55:38 -07:00
if (setjmp(buf) == 0) {
const int kType = var->getKeyType();
const int vType = var->getValueType();
2017-04-27 03:55:38 -07:00
if (vType == LUA_TTABLE) {
if (kType == LUA_TNUMBER) {
lua_pushnumber(mL, QString(var->getName()).toDouble());
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE) {
lua_rawgeti(mL, LUA_REGISTRYINDEX, var->getName().toInt());
2017-04-27 03:55:38 -07:00
} else {
lua_pushstring(mL, QString(var->getName()).toUtf8().constData());
}
if (lua_istable(mL, -2)) {
lua_gettable(mL, -2);
return true;
}
lua_pop(mL, 1);
return false;
}
if (vType == LUA_TNUMBER) {
lua_pushnumber(mL, QString(var->getValue()).toDouble());
2017-04-27 03:55:38 -07:00
} else if (vType == LUA_TBOOLEAN) {
lua_pushboolean(mL, var->getValue().toLower() == "true" ? 1 : 0);
2017-04-27 03:55:38 -07:00
} else if (vType == LUA_TSTRING) {
lua_pushstring(mL, QString(var->getName()).toUtf8().constData());
2017-04-27 03:55:38 -07:00
} else {
return false;
2017-04-27 03:55:38 -07:00
}
} else {
Improve: error messages for easier troubleshooting (#8721) #### Brief overview of PR changes/additions Adds detailed error messages with context to help diagnose issues: - Process startup failures now show working directory and PATH - GMCP authentication errors show the package name and malformed data - Lua variable operations show variable names and type information - File/directory operations report specific failures #### Motivation for adding to Mudlet When something goes wrong, vague error messages make troubleshooting difficult. These improvements help both users and game admins quickly identify the root cause of issues. #### Other info (issues closed, discussion etc) Test cases: - Try to start a non-existent process via Lua - Connect to a game server sending malformed GMCP auth JSON - Trigger Lua variable rename with unsupported key types (this one would be hard to do, UI doesnt allow it) Sample error messages: ``` Failed to start process 'python3': No such file or directory. Working directory: '/home/user/.config/mudlet/profiles/MyGame'. PATH: '/usr/local/bin:/usr/bin:/bin' GMCP Char.Login.Result - Failed to parse JSON: illegal value at offset 15. Received data: "{invalid: json}" GMCP Char.Login.Result - Expected JSON object but got null. LuaInterface::renameCVar() - Unsupported key type: boolean for variable "myVar". Expected string, number, or table. LuaInterface::loadValue() - Value at stack index 2 is not a table for variable "config". Got type: string. Host: failed to create error log directory: /home/user/.config/mudlet/profiles/MyGame/log ``` --------- Co-authored-by: Claude <noreply@anthropic.com>
2026-01-03 16:00:41 +01:00
qWarning().noquote().nospace() << "LuaInterface::loadVar() - Lua panic occurred while loading variable \"" << var->getName() << "\" with key type " << lua_typename(mL, var->getKeyType())
<< " and value type " << lua_typename(mL, var->getValueType()) << ".";
return false;
}
2013-08-19 12:25:26 +02:00
return true;
}
2017-04-27 03:55:38 -07:00
void LuaInterface::renameVar(TVar* var)
{
//this assumes anything like reparenting has been done
2017-04-27 03:55:38 -07:00
QList<TVar*> vars = varOrder(var);
QString oldVariable = vars.at(0)->getName();
QString newName;
if (vars.size() > 1) {
newName = vars[0]->getName();
}
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
2017-04-27 03:55:38 -07:00
for (int i = 1; i < vars.size(); i++) {
const int kType = vars[i]->getKeyType();
// numbers and booleans use unquoted subscripts: t[3.14], t[true]
if (kType == LUA_TNUMBER || kType == LUA_TBOOLEAN) {
oldVariable.append(qsl("[%1]").arg(vars.at(i)->getName()));
if (i < vars.size() - 1) {
newName.append(qsl("[%1]").arg(vars[i]->getName()));
}
2017-04-27 03:55:38 -07:00
} else if (kType == LUA_TTABLE) {
renameCVar(vars);
return;
} else {
// that leaves LUA_TSTRING
oldVariable.append(qsl(R"(["%1"])").arg(vars.at(i)->getName()));
if (i < vars.size() - 1) {
newName.append(qsl(R"(["%1"])").arg(vars.at(i)->getName()));
}
}
}
if (vars.size() <= 1) {
// this variable is at root level on _G
newName.append(qsl("_G[\"%1\"]").arg(vars.last()->getNewName()));
2017-04-27 03:55:38 -07:00
} else {
// this variable is nested in a table
if (var->getNewKeyType() == LUA_TNUMBER || var->getNewKeyType() == LUA_TBOOLEAN) {
newName.append(qsl("[%1]").arg(vars.last()->getNewName()));
} else {
newName.append(qsl(R"(["%1"])").arg(vars.last()->getNewName()));
}
2017-04-27 03:55:38 -07:00
}
auto renameCode = qsl("%1 = %2").arg(newName, oldVariable);
int error = luaL_loadstring(mL, renameCode.toUtf8().constData());
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
if (error) {
qWarning().noquote().nospace() << "LuaInterface::renameVar(...) WARNING - In copying (first) stage, internal Lua (parsing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\"" << renameCode
<< "\".";
var->clearNewName();
return;
}
error = lua_pcall(mL, 0, LUA_MULTRET, 0);
2017-04-27 03:55:38 -07:00
if (error) {
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
qWarning().noquote().nospace() << "LuaInterface::renameVar(...) WARNING - In copying (first) stage, internal Lua (executing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\""
<< renameCode << "\".";
var->clearNewName();
return;
}
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
//delete it
error = luaL_loadstring(mL, oldVariable.append(QLatin1String(" = nil")).toUtf8().constData());
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
if (error) {
qWarning().noquote().nospace() << "LuaInterface::renameVar(...) WARNING - In deleting (second) stage, internal Lua (parsing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\""
<< renameCode << "\".";
var->clearNewName();
return;
}
error = lua_pcall(mL, 0, LUA_MULTRET, 0);
2017-04-27 03:55:38 -07:00
if (error) {
BugFix: attempt to fix some High and Medium Impact Coverity Issues (#3837) Classed as "High Impact": CID Type Detail 1492499 "Uninitialized scalar variable (UNINIT) "5. uninit_use: Using uninitialized value error." 1485860 "No virtual destructor" "A1. dtor_in_derived: Class `XMLimport` has a compiler-generated destructor. It is non-empty because of its field `mpHost`. A pointer to class `XMLimport` is upcast to class `QXmlStreamReader` which doesn't have a virtual destructor." Classed as "Medium Impact": 1492834 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mIsEndTag` is not initialized in this constructor nor in any functions that it calls. 4. uninit_member: Non-static class member `mIsEmptyTag` is not initialized in this constructor nor in any functions that it calls. 6. uninit_member: Non-static class member `mReadingAttrValue` is not initialized in this constructor nor in any functions that it calls. 8. uninit_member: Non-static class member `mOpeningQuote` is not initialized in this constructor nor in any functions that it calls." 1488910 "Uninitialized scalar field (UNINIT_CTOR)" "2. uninit_member: Non-static class member `mPlayerRoomStyle` is not initialized in this constructor nor in any functions that it calls." "4. uninit_member: Non-static class member `mPlayerRoomOuterDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." "6. uninit_member: Non-static class member `mPlayerRoomInnerDiameterPercentage` is not initialized in this constructor nor in any functions that it calls." 1478854 "Uninitialized pointer field (UNINIT_CTOR)" "4. uninit_member: Non-static class member `mpOutOfBandDataIncomingCodec` is not initialized in this constructor nor in any functions that it calls." 1468478 "Unchecked return value (CHECKED_RETURN)" "10. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468477 "Unchecked return value (CHECKED_RETURN)" "14. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." 1468474 "Unchecked return value (CHECKED_RETURN)" "16. check_return: Calling `luaL_loadstring` without checking return value (as is done elsewhere 17 out of 21 times)." - x 2 1468468 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return 1;`" 1415097 "Dereference null return value (NULL_RETURNS)" "8. dereference: Dereferencing timer, which is known to be `nullptr`" 1415092 "Identical code for different branches (IDENTICAL_BRANCHES)" "identical_branches: The same code is executed regardless of whether `areaExit` is true, because the 'then' and 'else' branches are identical. Should one of the branches be modified, or the entire 'if' statement replaced?" 1415023 "Dereference null return value (NULL_RETURNS)" "26. dereference: Dereferencing a pointer that might be `nullptr` `pR->name` when calling `QString`. 1414989 "Explicit null dereferenced (FORWARD_NULL)" "81. var_deref_op: Dereferencing null pointer `this->originalExits.value(dirCode, TExit * const(NULL))`." x 11 1414977 "Logically dead code (DEADCODE)" "dead_error_line: Execution cannot reach this statement: `return false;`." Also removed unused: * (int) cTelnet::curX & curY, * (double) cTelnet::networkLatencyMin & networkLatencyMax * (QMutex) TimerUnit::mTimerUnitLock Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-06-01 17:35:35 +01:00
qWarning().noquote().nospace() << "LuaInterface::renameVar(...) WARNING - In deleting (second) stage, internal Lua (executing) error: \"" << lua_tostring(mL, -1) << "\" in code:\n\""
<< renameCode << "\".";
}
var->clearNewName();
}
// returns the value for a string/number/boolean datatype, or an empty string otherwise
2017-04-27 03:55:38 -07:00
QString LuaInterface::getValue(TVar* var)
{
if (setjmp(buf) == 0) {
QList<TVar*> const vars = varOrder(var);
if (vars.empty()) {
return {};
}
const int pCount = vars.size(); //how many things we need to pop from the stack at the end
//load from _G first
auto firstVariable = vars.constFirst();
if (firstVariable->getKeyType() == LUA_TSTRING) {
lua_getglobal(mL, (firstVariable->getName()).toUtf8().constData());
} else if (firstVariable->getKeyType() == LUA_TNUMBER) {
lua_pushnumber(mL, firstVariable->getName().toDouble());
lua_gettable(mL, LUA_GLOBALSINDEX);
} else if (firstVariable->getKeyType() == LUA_TBOOLEAN) {
lua_pushboolean(mL, firstVariable->getName().toLower() == "true" ? 1 : 0);
lua_gettable(mL, LUA_GLOBALSINDEX);
}
if (lua_isnoneornil(mL, lua_gettop(mL))) {
qDebug() << "LuaInterface::getValue: Couldn't put root value" << firstVariable->getName() << "onto the Lua stack in order to get value of" << var->getName()
<< ", perhaps the key type isn't supported?";
return {};
}
2017-04-27 03:55:38 -07:00
for (int i = 1; i < vars.size(); i++) {
if (!loadValue(mL, vars.at(i), -2)) {
return {};
}
}
const int valueType = lua_type(mL, -1);
QString value;
if (valueType == LUA_TBOOLEAN) {
value = lua_toboolean(mL, -1) == 0 ? QLatin1String("false") : QLatin1String("true");
} else if (valueType == LUA_TNUMBER || valueType == LUA_TSTRING) {
value = lua_tostring(mL, -1);
}
lua_pop(mL, pCount);
return value;
}
return {};
}
2017-04-27 03:55:38 -07:00
void LuaInterface::iterateTable(lua_State* L, int index, TVar* tVar, bool hide)
{
depth++;
2017-04-27 03:55:38 -07:00
while (lua_next(L, index)) {
const int vType = lua_type(L, -1);
const int kType = lua_type(L, -2);
2017-04-27 03:55:38 -07:00
lua_pushvalue(L, -2); //we do this because extracting the key with tostring changes it
QString keyName;
QString valueName;
auto var = new TVar();
2017-04-27 03:55:38 -07:00
if (kType == LUA_TTABLE) {
keyName = QString::number(luaL_ref(L, LUA_REGISTRYINDEX)); //this function pops the top item
lrefs.append(keyName.toInt());
var->setReference(true);
} else if (kType == LUA_TBOOLEAN) {
//lua_tostring() returns NULL for booleans, name the key ourselves
keyName = lua_toboolean(L, -1) ? qsl("true") : qsl("false");
lua_pop(L, 1);
2017-04-27 03:55:38 -07:00
} else {
keyName = lua_tostring(L, -1);
2017-04-27 03:55:38 -07:00
if (kType == LUA_TFUNCTION && keyName.isEmpty()) {
//we lost the reference
keyName = QString::number(luaL_ref(L, LUA_REGISTRYINDEX));
lrefs.append(keyName.toInt());
var->setReference(true);
2017-04-27 03:55:38 -07:00
} else {
lua_pop(L, 1);
2017-04-27 03:55:38 -07:00
}
}
2017-04-27 03:55:38 -07:00
if (keyName == "package" && depth == 1) { //don't load in the 'package' table
lua_pop(L, 1);
tVar->removeChild(var);
delete var;
continue;
}
var->setName(keyName, kType);
var->setValueType(vType);
var->setParent(tVar);
var->hidden = hide;
tVar->addChild(var);
const void* pKey = lua_topointer(L, -1);
var->pKey = pKey;
const void* pValue = lua_topointer(L, -2);
var->pValue = pValue;
if (varUnit->varExists(var) || keyName == qsl("_G")) {
lua_pop(L, 1);
tVar->removeChild(var);
delete var;
continue;
}
varUnit->addVariable(var);
varUnit->addPointer(pKey);
varUnit->addPointer(pValue);
2017-04-27 03:55:38 -07:00
if (vType == LUA_TTABLE) {
if (depth <= 99 && lua_checkstack(L, 3)) { //depth is historical now
//put the table on top
lua_pushnil(L);
var->setValue("{}", LUA_TTABLE);
iterateTable(L, -2, var, hide);
depth--;
}
2017-04-27 03:55:38 -07:00
} else if (vType == LUA_TSTRING || vType == LUA_TNUMBER) {
lua_pushvalue(L, -1);
valueName = lua_tostring(L, -1);
var->setValue(valueName);
2017-04-27 03:55:38 -07:00
lua_pop(L, 1);
} else if (vType == LUA_TBOOLEAN) {
valueName = lua_toboolean(L, -1) == 0 ? "false" : "true";
var->setValue(valueName);
2017-04-27 03:55:38 -07:00
} else if (vType == LUA_TFUNCTION
&& (!keyName.toLower().startsWith("alias") && !keyName.toLower().startsWith("trigger") && !keyName.toLower().startsWith("action") && !keyName.toLower().startsWith("timer")
&& !keyName.toLower().startsWith("key"))) {
//functions are compiled to bytecode so there is no reference
var->setValue("function");
2017-04-27 03:55:38 -07:00
} else {
tVar->removeChild(var);
varUnit->removeVariable(var);
delete var;
}
lua_pop(L, 1);
}
}
2017-04-27 03:55:38 -07:00
void LuaInterface::getVars(bool hide)
{
//returns the base item
Cleanup: replace obsoleted QTime::elapsed() with QElapsedTimer::elapsed() (#4400) The latter has been present since Qt 4.7 and even on some Windows OSes where it may be a 32-Bit value that can overflow after nearly 50 days when the lower quality TickCounter clock is used as a fallback instead of the PerformanceCounter one this is a better bet than the QTime based one that will overflow (wrap) after 24 hours and will be affected by Summer-Time changes and user/system adjustment of the system clock. Also: * rename three elements related to timing the network latency, their original names were somewhat ambiguous: * (QLineEdit*) TConsole::networkLatency ==> TConsole::mpLineEdit_networkLatency * (double) cTelnet::networkLatency ==> cTelnet::networkLatencyTime * (QTime) cTelnet::networkLatencyTime ==> (QElapsedTimer) cTelnet::networkLatencyTimer * rename some other elements in a comparable way: * (QTime) cTelnet::timeOffset ==> (QElapsedTimer) cTelnet::mRecordingChunkTimer * (QTime) cTelnet::mConnectionTime ==> (QElapsedTimer) cTelnet::mConnectionTimer * (int) cTelnet::lastTimeOffset ==> (int) cTelnet::mRecordLastChunkMSecTimeOffset * simplify a C string array access - there is no need to use the address operator AND an index when referring to the start of a C array, i.e. for char buffer[datalen]: '&buffer[0]' is simply 'buffer' ! * the display of the network latency (if available) and the system processing time is a UI feature but it was not being put through the translation system, this commit now allows for that to happen. This should remove 12 warnings (on my Linux Qt 5.14.2 system). Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-11-26 20:54:01 +00:00
// QElapsedTimer t;
// t.start();
fix: two ways a profile save could lose or resurrect your data (#9704) #### Brief overview of PR changes/additions - Variables: the export skipped its refresh whenever the editor's Variables view was on screen, so anything a script wrote into a saved variable while it sat open was dropped from the save - including the session's last save, which is taken with whatever view the editor was left on. The variables are now read into a throwaway tree, which also stops a save stranding the editor's variable search results. - Packages: a save taken while a unit was still executing an item of a package that had just been uninstalled wrote that package's items back into the profile, where they returned as orphans the Package Manager could not remove. The XML writers now skip what the units have queued for a deferred delete, the module writer included - reloading a module from a script used to write both the pre- and post-reload copies of its items into the module file. - `LuaInterface::getVars()` is now `setjmp`-guarded like every other Lua-touching method there, so a panic cannot jump past the export's scope with its variable tree and registry references still held. #### Motivation for adding to Mudlet Both are silent data loss in everyday use: quitting with the editor on the Variables tab, and the `mpkg`/auto-updater shape of uninstalling a package from a script. #### Other info (issues closed, discussion etc) From the 5.0 QA sweep, findings C13 and C14. The variables half re-opens the loss that `20009c5ec` "fix: variables added while playing are no longer lost when saving (#9492)" fixed, via the guard it added; the packages half is the missing counterpart to the self-uninstall deferral in `276e8bbfd` (#9383) and its follow-ups. #9492's own cases still pass unchanged. **Test case:** create a table from the command line, tick it to be saved in the editor's Variables view, leave the editor there, run `lua myTable.later = "x"`, quit and reopen - `later` is still there. `ctest -R 'XMLexportVariablesTest|PackageSelfUninstallTest'` covers both halves; all 12 new cases were verified to fail against the unfixed source. Assisted-by: Claude:claude-opus-5
2026-08-07 10:14:45 +02:00
// onPanic() longjmp()s to the shared buf, so without a setjmp of our own
// that jump lands in whichever frame set it last - usually one that has
// already returned, taking the caller's scope down with it.
if (setjmp(buf) != 0) {
qWarning() << "LuaInterface::getVars() WARNING - Lua panicked while reading the variables in; the variable tree is incomplete.";
return;
}
lua_pushnil(mL);
depth = 0;
auto global = new TVar();
global->setName("_G", LUA_TSTRING);
global->setValue("{}", LUA_TTABLE);
fix: two ways a profile save could lose or resurrect your data (#9704) #### Brief overview of PR changes/additions - Variables: the export skipped its refresh whenever the editor's Variables view was on screen, so anything a script wrote into a saved variable while it sat open was dropped from the save - including the session's last save, which is taken with whatever view the editor was left on. The variables are now read into a throwaway tree, which also stops a save stranding the editor's variable search results. - Packages: a save taken while a unit was still executing an item of a package that had just been uninstalled wrote that package's items back into the profile, where they returned as orphans the Package Manager could not remove. The XML writers now skip what the units have queued for a deferred delete, the module writer included - reloading a module from a script used to write both the pre- and post-reload copies of its items into the module file. - `LuaInterface::getVars()` is now `setjmp`-guarded like every other Lua-touching method there, so a panic cannot jump past the export's scope with its variable tree and registry references still held. #### Motivation for adding to Mudlet Both are silent data loss in everyday use: quitting with the editor on the Variables tab, and the `mpkg`/auto-updater shape of uninstalling a package from a script. #### Other info (issues closed, discussion etc) From the 5.0 QA sweep, findings C13 and C14. The variables half re-opens the loss that `20009c5ec` "fix: variables added while playing are no longer lost when saving (#9492)" fixed, via the guard it added; the packages half is the missing counterpart to the self-uninstall deferral in `276e8bbfd` (#9383) and its follow-ups. #9492's own cases still pass unchanged. **Test case:** create a table from the command line, tick it to be saved in the editor's Variables view, leave the editor there, run `lua myTable.later = "x"`, quit and reopen - `later` is still there. `ctest -R 'XMLexportVariablesTest|PackageSelfUninstallTest'` covers both halves; all 12 new cases were verified to fail against the unfixed source. Assisted-by: Claude:claude-opus-5
2026-08-07 10:14:45 +02:00
releaseVariableReferences();
varUnit->clear();
varUnit->setBase(global);
varUnit->addVariable(global);
iterateTable(mL, LUA_GLOBALSINDEX, global, hide);
Cleanup: replace obsoleted QTime::elapsed() with QElapsedTimer::elapsed() (#4400) The latter has been present since Qt 4.7 and even on some Windows OSes where it may be a 32-Bit value that can overflow after nearly 50 days when the lower quality TickCounter clock is used as a fallback instead of the PerformanceCounter one this is a better bet than the QTime based one that will overflow (wrap) after 24 hours and will be affected by Summer-Time changes and user/system adjustment of the system clock. Also: * rename three elements related to timing the network latency, their original names were somewhat ambiguous: * (QLineEdit*) TConsole::networkLatency ==> TConsole::mpLineEdit_networkLatency * (double) cTelnet::networkLatency ==> cTelnet::networkLatencyTime * (QTime) cTelnet::networkLatencyTime ==> (QElapsedTimer) cTelnet::networkLatencyTimer * rename some other elements in a comparable way: * (QTime) cTelnet::timeOffset ==> (QElapsedTimer) cTelnet::mRecordingChunkTimer * (QTime) cTelnet::mConnectionTime ==> (QElapsedTimer) cTelnet::mConnectionTimer * (int) cTelnet::lastTimeOffset ==> (int) cTelnet::mRecordLastChunkMSecTimeOffset * simplify a C string array access - there is no need to use the address operator AND an index when referring to the start of a C array, i.e. for char buffer[datalen]: '&buffer[0]' is simply 'buffer' ! * the display of the network latency (if available) and the system processing time is a UI feature but it was not being put through the translation system, this commit now allows for that to happen. This should remove 12 warnings (on my Linux Qt 5.14.2 system). Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2020-11-26 20:54:01 +00:00
// FIXME: possible to keep and report? qDebug()<<"took"<<t.elapsed()<<"to get variables in";
}