From 96facaa7bbcc477a4b75c5e5617fc10ac323a666 Mon Sep 17 00:00:00 2001 From: dgelessus Date: Fri, 15 Dec 2023 01:03:25 +0100 Subject: [PATCH] Make Python.Cheat command more usable by not parsing its argument The argument is now always treated as a plain string and passed directly to the cheat. This is the behavior expected by all the functions in xCheat.py, which parse the string argument manually where needed. The previous implementation evaluated the argument value as a Python expression. This theoretically allowed passing non-string arguments, but none of the cheats use this (and it's also a potential code execution issue). If no argument was passed, the function was called with no arguments, which is also not supported by any of the cheats. In practice, this required unintuitive syntax for calling the cheats correctly, for example: Python.Cheat GetPlayerID None Python.Cheat GetSDL "'FirstWeekClothing'" With the new argument handling, these have been simplified to: Python.Cheat GetPlayerID Python.Cheat GetSDL FirstWeekClothing --- .../pfConsole/pfConsoleCommands.cpp | 11 ++--- .../FeatureLib/pfPython/cyPythonInterface.cpp | 42 ++++++++----------- .../FeatureLib/pfPython/cyPythonInterface.h | 4 +- 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp index c2a96a24..340b4846 100644 --- a/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp +++ b/Sources/Plasma/FeatureLib/pfConsole/pfConsoleCommands.cpp @@ -7061,17 +7061,12 @@ PF_CONSOLE_CMD( Python, "string functions, ...", // Params "Run a cheat command" ) { - std::string extraParms; + const char* extraParms = ""; if (numParams > 1) { - extraParms = "("; - extraParms.append(params[1]); - extraParms.append(",)"); + extraParms = params[1]; } - else - extraParms = "()"; - - PythonInterface::RunFunctionSafe("xCheat", params[0], extraParms.c_str()); + PythonInterface::RunFunctionStringArg("xCheat", params[0], extraParms); std::string output; // get the messages diff --git a/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.cpp b/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.cpp index 1d90fd88..569a48de 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.cpp @@ -2102,38 +2102,32 @@ PyObject* PythonInterface::RunFunction(PyObject* module, const char* name, PyObj return result; } -PyObject* PythonInterface::ParseArgs(const char* args) -{ - PyObject* result = NULL; - PyObject* scope = PyDict_New(); - if (scope) - { - //- Py_eval_input makes this function accept only single expresion (not statement) - //- When using empty scope, functions and classes like 'file' or '__import__' are not visible - result = PyRun_String(args, Py_eval_input, scope, NULL); - Py_DECREF(scope); - } - - return result; -} - -bool PythonInterface::RunFunctionSafe(const char* module, const char* function, const char* args) +bool PythonInterface::RunFunctionStringArg(const char* module, const char* name, const char* arg) { PyObject* moduleObj = ImportModule(module); bool result = false; if (moduleObj) { - PyObject* argsObj = ParseArgs(args); - if (argsObj) + PyObject* argObj = PyString_FromString(arg); + if (argObj) { - PyObject* callResult = RunFunction(moduleObj, function, argsObj); - if (callResult) + PyObject* argsObj = PyTuple_New(1); + if (argsObj) { - result = true; - Py_DECREF(callResult); + // PyTuple_SET_ITEM steals the reference to argObj. + PyTuple_SET_ITEM(argsObj, 0, argObj); + PyObject* callResult = RunFunction(moduleObj, name, argsObj); + if (callResult) + { + result = true; + Py_DECREF(callResult); + } + Py_DECREF(argsObj); + } + else + { + Py_DECREF(argObj); } - - Py_DECREF(argsObj); } Py_DECREF(moduleObj); } diff --git a/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.h b/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.h index 8e73f1a9..335db92a 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.h +++ b/Sources/Plasma/FeatureLib/pfPython/cyPythonInterface.h @@ -223,9 +223,7 @@ public: static PyObject* RunFunction(PyObject* module, const char* name, PyObject* args); - static PyObject* ParseArgs(const char* args); - - static bool RunFunctionSafe(const char* module, const char* function, const char* args); + static bool RunFunctionStringArg(const char* module, const char* name, const char* arg); ///////////////////////////////////////////////////////////////////////////// //