From db96d13453db0b20a16b1cf272318d64316731b3 Mon Sep 17 00:00:00 2001 From: John Hernandez <129467592+H3rnand3zzz@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:59:53 +0100 Subject: [PATCH] Improve string convertion error handling Before the change, profanity has shown `TypeError: prof_pre_chat_message_display() missing 3 required positional arguments: 'barejid', 'resource', and 'message'` error for received messages with incorrect encoding instead of proper error handling for string convertion. That is a temporary fix, correct fix probably would be passing potentially problematic char* as `bytes` (using `y` instead of `s` format), but this would require API changes and hence correction of plugins to handle new input parameters properly (likely with "decode" function). A bit hard to reproduce. You need to add a plugin with the following code (or any other plugin with `prof_pre_chat_message_display` present, such as emoticons.py): ```python def prof_pre_chat_message_display(barejid, resource, message): return message ``` and then receive/send message with incorrectly encoded character, it can be any invalid UTF8 symbol. You'll see error in console, errors don't represent actual errors in plugins, but rather Profanity's shortcoming, though it make appear so that the problem is in plugin. Actual proper handling would likely be using `y` instead of `s` format (see [reference](https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue)) > s ([str](https://docs.python.org/3/library/stdtypes.html#str) or None) [const char *] > Convert a null-terminated C string to a Python [str](https://docs.python.org/3/library/stdtypes.html#str) object using 'utf-8' encoding. If the C string pointer is NULL, None is used. to > y ([bytes](https://docs.python.org/3/library/stdtypes.html#bytes)) [const char *] > This converts a C string to a Python [bytes](https://docs.python.org/3/library/stdtypes.html#bytes) > object. If the C string pointer is NULL, None is returned. since there is a [problem](https://docs.python.org/3/c-api/arg.html) with `s`: > s ([str](https://docs.python.org/3/library/stdtypes.html#str)) [const char *] > Convert a Unicode object to a C pointer to a character string. > A pointer to an existing string is stored in the character pointer variable whose address you pass. > ... Unicode objects are converted to C strings using 'utf-8' encoding. > **If this conversion fails**, a [UnicodeError](https://docs.python.org/3/library/exceptions.html#UnicodeError) is raised. In python such problem can be handled using `errors='ignore'` in [bytes.decode](https://docs.python.org/3/library/stdtypes.html#bytes.decode) or in a more sophisticated manner, depending on needs and realization. --- src/plugins/python_plugins.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 43e37e6a..c999afa3 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -318,6 +318,11 @@ python_pre_chat_message_display_hook(ProfPlugin* plugin, const char* const barej { disable_python_threads(); PyObject* p_args = Py_BuildValue("sss", barejid, resource, message); + if (!p_args) { + log_warning("Unable to convert strings in `python_pre_chat_message_display_hook` to 'UTF8'. barejid: %s, resource: %s, message: %s", barejid, resource, message); + allow_python_threads(); + return NULL; + } PyObject* p_function; PyObject* p_module = plugin->module; @@ -408,6 +413,12 @@ python_pre_room_message_display_hook(ProfPlugin* plugin, const char* const barej { disable_python_threads(); PyObject* p_args = Py_BuildValue("sss", barejid, nick, message); + if (!p_args) { + log_warning("Unable to convert strings in `python_pre_room_message_display_hook` to 'UTF8'. barejid: %s, nick: %s, message: %s", barejid, nick, message); + allow_python_threads(); + return NULL; + } + PyObject* p_function; PyObject* p_module = plugin->module;