diff --git a/src/_Plugin_Helper.cpp b/src/_Plugin_Helper.cpp index 5c720cc64..be78161d7 100644 --- a/src/_Plugin_Helper.cpp +++ b/src/_Plugin_Helper.cpp @@ -15,6 +15,117 @@ PluginTaskData_base *Plugin_task_data[TASKS_MAX] = {}; +#if DEBUG_PCONFIG_RANGE_CHECK + +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define DEBUG_PCONFIG_RANGE_CHECK_args max_n, event, n, linenr, filename +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define DEBUG_PCONFIG_RANGE_CHECK_args max_n, event, n, linenr +# else +# define DEBUG_PCONFIG_RANGE_CHECK_args max_n, event, n +# endif + +bool PCONFIGxxx_outOfBounds( + const __FlashStringHelper *prefix, + const uint8_t max_n, + DEBUG_PCONFIG_RANGE_CHECK_args_decl) +{ + if (validTaskIndex(event->TaskIndex) && (n < max_n)) { return false; } + + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + const auto pluginID = getPluginID_from_TaskIndex(event->TaskIndex); +# if DEBUG_PCONFIG_RANGE_CHECK > 1 + addLog(LOG_LEVEL_ERROR, strformat( + F("%s(%u) out of range (range: 0..%u) for taskIndex %u (%s: %s) (%s:%u)"), + FsP(prefix), + n, + max_n - 1, + event->TaskIndex + 1, + pluginID.toDisplayString().c_str(), + getPluginNameFromPluginID(pluginID).c_str(), +# if DEBUG_PCONFIG_RANGE_CHECK > 2 + FsP(filename), +# else + FsP(F("line")), +# endif + linenr)); +# else + addLog(LOG_LEVEL_ERROR, strformat( + F("%s(%u) out of range (range: 0..%u) for taskIndex %u (%s: %s)"), + FsP(prefix), + n, + max_n - 1, + event->TaskIndex + 1, + pluginID.toDisplayString().c_str(), + getPluginNameFromPluginID(pluginID).c_str())); +# endif + } + return true; +} + +int16_t& do_PCONFIG(DEBUG_PCONFIG_RANGE_CHECK_args_decl) +{ + constexpr uint8_t max_n = NR_ELEMENTS(Settings.TaskDevicePluginConfig[0]); + + if (!PCONFIGxxx_outOfBounds(F("PCONFIG"), DEBUG_PCONFIG_RANGE_CHECK_args)) { + return Settings.TaskDevicePluginConfig[event->TaskIndex][n]; + } + static int16_t invalid{}; + invalid = 0; + return invalid; +} + +float& do_PCONFIG_FLOAT(DEBUG_PCONFIG_RANGE_CHECK_args_decl) +{ + constexpr uint8_t max_n = NR_ELEMENTS(Settings.TaskDevicePluginConfigFloat[0]); + + if (!PCONFIGxxx_outOfBounds(F("PCONFIG_FLOAT"), DEBUG_PCONFIG_RANGE_CHECK_args)) { + return Settings.TaskDevicePluginConfigFloat[event->TaskIndex][n]; + } + + static float invalid{}; + invalid = 0; + return invalid; +} + +int32_t& do_PCONFIG_LONG(DEBUG_PCONFIG_RANGE_CHECK_args_decl) +{ + constexpr uint8_t max_n = NR_ELEMENTS(Settings.TaskDevicePluginConfigLong[0]); + + if (!PCONFIGxxx_outOfBounds(F("PCONFIG_LONG"), DEBUG_PCONFIG_RANGE_CHECK_args)) { + return Settings.TaskDevicePluginConfigLong[event->TaskIndex][n]; + } + static int32_t invalid{}; + invalid = 0; + return invalid; +} + +uint32_t& do_PCONFIG_ULONG(DEBUG_PCONFIG_RANGE_CHECK_args_decl) +{ + constexpr uint8_t max_n = NR_ELEMENTS(Settings.TaskDevicePluginConfigULong[0]); + + if (!PCONFIGxxx_outOfBounds(F("PCONFIG_ULONG"), DEBUG_PCONFIG_RANGE_CHECK_args)) { + return Settings.TaskDevicePluginConfigULong[event->TaskIndex][n]; + } + static uint32_t invalid{}; + invalid = 0; + return invalid; +} + +int8_t& do_PIN(DEBUG_PCONFIG_RANGE_CHECK_args_decl) +{ + constexpr uint8_t max_n = 3; + + if (!PCONFIGxxx_outOfBounds(F("PIN"), DEBUG_PCONFIG_RANGE_CHECK_args)) { + // N.B. order of array indices taskIndex_t and n differs from the other PCONFIGxxx + return Settings.TaskDevicePin[n][event->TaskIndex]; + } + static int8_t invalid{}; + invalid = -1; + return invalid; +} + +#endif // if DEBUG_PCONFIG_RANGE_CHECK String PCONFIG_LABEL(int n) { if (n < PLUGIN_CONFIGVAR_MAX) { @@ -47,9 +158,9 @@ bool initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { } // 2nd heap may have been active to allocate the PluginTaskData, but here we need to keep the default heap active - # ifdef USE_SECOND_HEAP +#ifdef USE_SECOND_HEAP HeapSelectDram ephemeral; - # endif // ifdef USE_SECOND_HEAP +#endif // ifdef USE_SECOND_HEAP clearPluginTaskData(taskIndex); @@ -59,18 +170,20 @@ bool initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { Plugin_task_data[taskIndex] = data; Plugin_task_data[taskIndex]->_taskdata_pluginID = Settings.getPluginID_for_task(taskIndex); - #if FEATURE_PLUGIN_STATS +#if FEATURE_PLUGIN_STATS const uint8_t valueCount = getValueCountForTask(taskIndex); + for (size_t i = 0; i < valueCount; ++i) { if (Cache.enabledPluginStats(taskIndex, i)) { Plugin_task_data[taskIndex]->initPluginStats(i); } } - #endif - #if FEATURE_PLUGIN_FILTER - // TODO TD-er: Implement init +#endif // if FEATURE_PLUGIN_STATS +#if FEATURE_PLUGIN_FILTER - #endif + // TODO TD-er: Implement init + +#endif // if FEATURE_PLUGIN_FILTER } else { delete data; @@ -81,7 +194,7 @@ bool initPluginTaskData(taskIndex_t taskIndex, PluginTaskData_base *data) { PluginTaskData_base* getPluginTaskData(taskIndex_t taskIndex) { if (pluginTaskData_initialized(taskIndex)) { - + if (!Plugin_task_data[taskIndex]->baseClassOnly()) { return Plugin_task_data[taskIndex]; } @@ -96,7 +209,6 @@ PluginTaskData_base* getPluginTaskDataBaseClassOnly(taskIndex_t taskIndex) { return nullptr; } - bool pluginTaskData_initialized(taskIndex_t taskIndex) { if (!validTaskIndex(taskIndex)) { return false; @@ -105,29 +217,22 @@ bool pluginTaskData_initialized(taskIndex_t taskIndex) { (Plugin_task_data[taskIndex]->_taskdata_pluginID == Settings.getPluginID_for_task(taskIndex)); } -String getPluginCustomArgName(int varNr) { - return getPluginCustomArgName(F("pc_arg"), varNr); -} +String getPluginCustomArgName(int varNr) { return getPluginCustomArgName(F("pc_arg"), varNr); } -String getPluginCustomArgName(const __FlashStringHelper * label, int varNr) { - return concat(label, varNr + 1); -} +String getPluginCustomArgName(const __FlashStringHelper *label, int varNr) { return concat(label, varNr + 1); } -int getFormItemIntCustomArgName(int varNr) { - return getFormItemInt(getPluginCustomArgName(varNr)); -} +int getFormItemIntCustomArgName(int varNr) { return getFormItemInt(getPluginCustomArgName(varNr)); } // Helper function to create formatted custom values for display in the devices overview page. // When called from PLUGIN_WEBFORM_SHOW_VALUES, the last item should add a traling div_br class // if the regular values should also be displayed. // The call to PLUGIN_WEBFORM_SHOW_VALUES should only return success = true when no regular values should be displayed // Note that the varNr of the custom values should not conflict with the existing variable numbers (e.g. start at VARS_PER_TASK) -void pluginWebformShowValue(taskIndex_t taskIndex, uint8_t varNr, const __FlashStringHelper * label, const String& value, bool addTrailingBreak) { - pluginWebformShowValue(taskIndex, varNr, String(label), value, addTrailingBreak); -} +void pluginWebformShowValue(taskIndex_t taskIndex, uint8_t varNr, const __FlashStringHelper *label, const String& value, + bool addTrailingBreak) { pluginWebformShowValue(taskIndex, varNr, String(label), value, addTrailingBreak); } void pluginWebformShowValue(taskIndex_t taskIndex, - uint8_t varNr, + uint8_t varNr, const String& label, const String& value, bool addTrailingBreak) { @@ -175,11 +280,12 @@ bool pluginOptionalTaskIndexArgumentMatch(taskIndex_t taskIndex, const String& s return found_taskIndex == taskIndex; } -bool pluginWebformShowGPIOdescription(taskIndex_t taskIndex, - const __FlashStringHelper * newline, - String& description) +bool pluginWebformShowGPIOdescription(taskIndex_t taskIndex, + const __FlashStringHelper *newline, + String & description) { struct EventStruct TempEvent(taskIndex); + TempEvent.String1 = newline; return PluginCall(PLUGIN_WEBFORM_SHOW_GPIO_DESCR, &TempEvent, description); } @@ -199,6 +305,7 @@ int checkDeviceVTypeForTask(struct EventStruct *event) { String dummy; event->idx = -1; + if (PluginCall(PLUGIN_GET_DEVICEVTYPE, event, dummy)) { return event->idx; // pconfig_index } diff --git a/src/_Plugin_Helper.h b/src/_Plugin_Helper.h index 9848ab0ed..6ebf764e9 100644 --- a/src/_Plugin_Helper.h +++ b/src/_Plugin_Helper.h @@ -49,11 +49,11 @@ #include "src/Helpers/_Plugin_Helper_serial.h" #if FEATURE_MQTT_DISCOVER -#include "src/Helpers/_CPlugin_Helper_mqtt.h" +# include "src/Helpers/_CPlugin_Helper_mqtt.h" #endif // if FEATURE_MQTT_DISCOVER #if FEATURE_PLUGIN_STATS -#include "src/PluginStructs/_StatsOnly_data_struct.h" +# include "src/PluginStructs/_StatsOnly_data_struct.h" #endif #include "src/WebServer/Chart_JS.h" @@ -62,43 +62,111 @@ #include "src/WebServer/Markup_Forms.h" #include "src/WebServer/ESPEasy_WebServer.h" +#if DEBUG_PCONFIG_RANGE_CHECK +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define DEBUG_PCONFIG_RANGE_CHECK_args_decl const struct EventStruct *event, uint8_t n, uint16_t linenr, \ + const __FlashStringHelper *filename +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define DEBUG_PCONFIG_RANGE_CHECK_args_decl const struct EventStruct *event, uint8_t n, uint16_t linenr +# else // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define DEBUG_PCONFIG_RANGE_CHECK_args_decl const struct EventStruct *event, uint8_t n +# endif // if DEBUG_PCONFIG_RANGE_CHECK > 2 + +int16_t & do_PCONFIG(DEBUG_PCONFIG_RANGE_CHECK_args_decl); +float & do_PCONFIG_FLOAT(DEBUG_PCONFIG_RANGE_CHECK_args_decl); +int32_t & do_PCONFIG_LONG(DEBUG_PCONFIG_RANGE_CHECK_args_decl); +uint32_t& do_PCONFIG_ULONG(DEBUG_PCONFIG_RANGE_CHECK_args_decl); +int8_t & do_PIN(DEBUG_PCONFIG_RANGE_CHECK_args_decl); +#endif // if DEBUG_PCONFIG_RANGE_CHECK + // Defines to make plugins more readable. - #ifndef PCONFIG - # define PCONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][(n)]) +# if DEBUG_PCONFIG_RANGE_CHECK +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG(n) do_PCONFIG(event, n, __LINE__, F(__FILE__)) +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define PCONFIG(n) do_PCONFIG(event, n, __LINE__) +# else // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG(n) do_PCONFIG(event, n) +# endif // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# else // if DEBUG_PCONFIG_RANGE_CHECK +# define PCONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][(n)]) +# endif // if DEBUG_PCONFIG_RANGE_CHECK #endif // ifndef PCONFIG #ifndef PCONFIG_FLOAT - # define PCONFIG_FLOAT(n) (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][(n)]) +# if DEBUG_PCONFIG_RANGE_CHECK +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG_FLOAT(n) do_PCONFIG_FLOAT(event, n, __LINE__, F(__FILE__)) +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define PCONFIG_FLOAT(n) do_PCONFIG_FLOAT(event, n, __LINE__) +# else // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG_FLOAT(n) do_PCONFIG_FLOAT(event, n) +# endif // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# else // if DEBUG_PCONFIG_RANGE_CHECK +# define PCONFIG_FLOAT(n) (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][(n)]) +# endif // if DEBUG_PCONFIG_RANGE_CHECK #endif // ifndef PCONFIG_FLOAT #ifndef PCONFIG_LONG - # define PCONFIG_LONG(n) (Settings.TaskDevicePluginConfigLong[event->TaskIndex][(n)]) +# if DEBUG_PCONFIG_RANGE_CHECK +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG_LONG(n) do_PCONFIG_LONG(event, n, __LINE__, F(__FILE__)) +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define PCONFIG_LONG(n) do_PCONFIG_LONG(event, n, __LINE__) +# else // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG_LONG(n) do_PCONFIG_LONG(event, n) +# endif // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# else // if DEBUG_PCONFIG_RANGE_CHECK +# define PCONFIG_LONG(n) (Settings.TaskDevicePluginConfigLong[event->TaskIndex][(n)]) +# endif // if DEBUG_PCONFIG_RANGE_CHECK #endif // ifndef PCONFIG_LONG #ifndef PCONFIG_ULONG - # define PCONFIG_ULONG(n) (Settings.TaskDevicePluginConfigULong[event->TaskIndex][(n)]) +# if DEBUG_PCONFIG_RANGE_CHECK +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG_ULONG(n) do_PCONFIG_ULONG(event, n, __LINE__, F(__FILE__)) +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define PCONFIG_ULONG(n) do_PCONFIG_ULONG(event, n, __LINE__) +# else // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PCONFIG_ULONG(n) do_PCONFIG_ULONG(event, n) +# endif // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# else // if DEBUG_PCONFIG_RANGE_CHECK +# define PCONFIG_ULONG(n) (Settings.TaskDevicePluginConfigULong[event->TaskIndex][(n)]) +# endif // if DEBUG_PCONFIG_RANGE_CHECK #endif // ifndef PCONFIG_ULONG #ifndef PIN // Please note the 'offset' of N compared to normal pin numbering. - # define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex]) +# if DEBUG_PCONFIG_RANGE_CHECK +# if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PIN(n) do_PIN(event, n, __LINE__, F(__FILE__)) +# elif DEBUG_PCONFIG_RANGE_CHECK > 1 +# define PIN(n) do_PIN(event, n, __LINE__) +# else // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# define PIN(n) do_PIN(event, n) +# endif // if DEBUG_PCONFIG_RANGE_CHECK > 2 +# else // if DEBUG_PCONFIG_RANGE_CHECK +# define PIN(n) (Settings.TaskDevicePin[n][event->TaskIndex]) +# endif // if DEBUG_PCONFIG_RANGE_CHECK #endif // ifndef PIN #ifndef CONFIG_PIN1 - # define CONFIG_PIN1 (Settings.TaskDevicePin1[event->TaskIndex]) +# define CONFIG_PIN1 (Settings.TaskDevicePin1[event->TaskIndex]) #endif // ifndef CONFIG_PIN1 #ifndef CONFIG_PIN2 - # define CONFIG_PIN2 (Settings.TaskDevicePin2[event->TaskIndex]) +# define CONFIG_PIN2 (Settings.TaskDevicePin2[event->TaskIndex]) #endif // ifndef CONFIG_PIN2 #ifndef CONFIG_PIN3 - # define CONFIG_PIN3 (Settings.TaskDevicePin3[event->TaskIndex]) +# define CONFIG_PIN3 (Settings.TaskDevicePin3[event->TaskIndex]) #endif // ifndef CONFIG_PIN3 #ifndef CONFIG_PORT - # define CONFIG_PORT (Settings.TaskDevicePort[event->TaskIndex]) +# define CONFIG_PORT (Settings.TaskDevicePort[event->TaskIndex]) #endif // ifndef CONFIG_PORT + extern PluginTaskData_base *Plugin_task_data[TASKS_MAX]; // Try to allocate in PSRAM or 2nd heap if possible -#define special_initPluginTaskData(I, T) void * ptr = special_calloc(1, sizeof(T)); if (ptr) { initPluginTaskData(I, new (ptr) T()); } +#define special_initPluginTaskData(I, T) void *ptr = special_calloc(1, sizeof(T)); \ + if (ptr) { initPluginTaskData(I, new (ptr) T()); } String PCONFIG_LABEL(int n); @@ -119,7 +187,8 @@ PluginTaskData_base* getPluginTaskDataBaseClassOnly(taskIndex_t taskIndex); bool pluginTaskData_initialized(taskIndex_t taskIndex); String getPluginCustomArgName(int varNr); -String getPluginCustomArgName(const __FlashStringHelper * label, int varNr); +String getPluginCustomArgName(const __FlashStringHelper *label, + int varNr); int getFormItemIntCustomArgName(int varNr); @@ -128,11 +197,11 @@ int getFormItemIntCustomArgName(int varNr); // if the regular values should also be displayed. // The call to PLUGIN_WEBFORM_SHOW_VALUES should only return success = true when no regular values should be displayed // Note that the varNr of the custom values should not conflict with the existing variable numbers (e.g. start at VARS_PER_TASK) -void pluginWebformShowValue(taskIndex_t taskIndex, - uint8_t varNr, - const __FlashStringHelper * label, - const String& value, - bool addTrailingBreak = false); +void pluginWebformShowValue(taskIndex_t taskIndex, + uint8_t varNr, + const __FlashStringHelper *label, + const String & value, + bool addTrailingBreak = false); void pluginWebformShowValue(taskIndex_t taskIndex, uint8_t varNr, @@ -158,9 +227,9 @@ bool pluginOptionalTaskIndexArgumentMatch(taskIndex_t taskIndex, const String& string, uint8_t paramNr); -bool pluginWebformShowGPIOdescription(taskIndex_t taskIndex, - const __FlashStringHelper * newline, - String& description); +bool pluginWebformShowGPIOdescription(taskIndex_t taskIndex, + const __FlashStringHelper *newline, + String & description); int getValueCountForTask(taskIndex_t taskIndex); diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 127a4cd24..17aea92d2 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -4651,4 +4651,25 @@ To create/register a plugin, you have to : #endif #endif // if !FEATURE_SPI && !FEATURE_I2C && !FEATURE_MODBUS && !FEATURE_CAN && !FEATURE_WRMBUS && !FEATURE_WIMBUS + + +#ifndef DEBUG_PCONFIG_RANGE_CHECK +// N.B. Build size increase compared to previous level, based on MAX builds 20260824 +// Size increase of level 3 depends also on path length of source files. +// 0: no range check (use for builds with already build size issues) +// 1: Basic range check, log when out of bounds (+1k) +// 2: Include line nr of file where error occured (+13k) +// 3: include filename + path of source file (+23k) +# ifndef BUILD_NO_DEBUG +# ifdef PLUGIN_BUILD_MAX_ESP32 +# define DEBUG_PCONFIG_RANGE_CHECK 3 +# else +# define DEBUG_PCONFIG_RANGE_CHECK 1 +# endif +# else +# define DEBUG_PCONFIG_RANGE_CHECK 0 +# endif +#endif + + #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H