From 0f10a13631700dace1473fd20b82388c2933fa2a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 5 Mar 2026 15:20:20 -1000 Subject: [PATCH] Use ifdef to split pre_setup signatures for const correctness When MAC suffix is not used, pre_setup takes const char* parameters so string literals stay in flash. When MAC suffix is used, it takes mutable char* for the static buffers that get overwritten with the actual MAC address. This avoids const_cast entirely. Also adds ESPHOME_NAME_ADD_MAC_SUFFIX define for static analysis. --- esphome/core/application.h | 39 +++++++++++++++++++++++--------------- esphome/core/config.py | 17 ++++++----------- esphome/core/defines.h | 1 + 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/esphome/core/application.h b/esphome/core/application.h index efac4d5aff0..ef30193607b 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -138,26 +138,35 @@ static constexpr uint32_t TEARDOWN_TIMEOUT_REBOOT_MS = 1000; // 1 second for qu class Application { public: - void pre_setup(char *name, size_t name_len, char *friendly_name, size_t friendly_name_len, bool name_add_mac_suffix) { +#ifdef ESPHOME_NAME_ADD_MAC_SUFFIX + /// Pre-setup with MAC suffix: overwrites placeholder in mutable static buffers with actual MAC. + void pre_setup(char *name, size_t name_len, char *friendly_name, size_t friendly_name_len) { arch_init(); - this->name_add_mac_suffix_ = name_add_mac_suffix; - if (name_add_mac_suffix) { - // MAC address length: 12 hex chars + null terminator - constexpr size_t mac_address_len = 13; - // MAC address suffix length (last 6 characters of 12-char MAC address string) - constexpr size_t mac_address_suffix_len = 6; - char mac_addr[mac_address_len]; - get_mac_address_into_buffer(mac_addr); - // Overwrite the placeholder suffix in the static buffers with actual MAC - memcpy(name + name_len - mac_address_suffix_len, mac_addr + mac_address_suffix_len, mac_address_suffix_len); - if (friendly_name_len > 0) { - memcpy(friendly_name + friendly_name_len - mac_address_suffix_len, mac_addr + mac_address_suffix_len, - mac_address_suffix_len); - } + this->name_add_mac_suffix_ = true; + // MAC address length: 12 hex chars + null terminator + constexpr size_t mac_address_len = 13; + // MAC address suffix length (last 6 characters of 12-char MAC address string) + constexpr size_t mac_address_suffix_len = 6; + char mac_addr[mac_address_len]; + get_mac_address_into_buffer(mac_addr); + // Overwrite the placeholder suffix in the mutable static buffers with actual MAC + memcpy(name + name_len - mac_address_suffix_len, mac_addr + mac_address_suffix_len, mac_address_suffix_len); + if (friendly_name_len > 0) { + memcpy(friendly_name + friendly_name_len - mac_address_suffix_len, mac_addr + mac_address_suffix_len, + mac_address_suffix_len); } this->name_ = StringRef(name, name_len); this->friendly_name_ = StringRef(friendly_name, friendly_name_len); } +#else + /// Pre-setup without MAC suffix: StringRef points directly at const string literals in flash. + void pre_setup(const char *name, size_t name_len, const char *friendly_name, size_t friendly_name_len) { + arch_init(); + this->name_add_mac_suffix_ = false; + this->name_ = StringRef(name, name_len); + this->friendly_name_ = StringRef(friendly_name, friendly_name_len); + } +#endif #ifdef USE_DEVICES void register_device(Device *device) { this->devices_.push_back(device); } diff --git a/esphome/core/config.py b/esphome/core/config.py index 08bb1252f2d..be3c6466e2e 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -568,11 +568,11 @@ async def to_code(config: ConfigType) -> None: """Create a name expression for pre_setup. With MAC suffix: emits a static mutable buffer with placeholder suffix. - Without: casts the string literal to char*. + Without: passes the string literal directly as const char*. Returns (expression, length). """ if not value: - return cg.RawExpression('(char *) ""'), 0 + return cg.RawExpression('""'), 0 if name_add_mac_suffix: value_with_placeholder = f"{value}{sep}XXXXXX" cg.add_global( @@ -581,10 +581,7 @@ async def to_code(config: ConfigType) -> None: ) ) return cg.RawExpression(var_name), len(value_with_placeholder) - return ( - cg.RawExpression(f"(char *) {cpp_string_escape(value)}"), - len(value), - ) + return cg.RawExpression(cpp_string_escape(value)), len(value) name_expr, name_len = _make_app_name_expr( name, _APP_NAME_BUF_VAR, _APP_NAME_MAC_SEP @@ -592,11 +589,9 @@ async def to_code(config: ConfigType) -> None: friendly_expr, friendly_len = _make_app_name_expr( friendly_name, _APP_FRIENDLY_NAME_BUF_VAR, _APP_FRIENDLY_NAME_MAC_SEP ) - cg.add( - cg.App.pre_setup( - name_expr, name_len, friendly_expr, friendly_len, name_add_mac_suffix - ) - ) + if name_add_mac_suffix: + cg.add_define("ESPHOME_NAME_ADD_MAC_SUFFIX") + cg.add(cg.App.pre_setup(name_expr, name_len, friendly_expr, friendly_len)) # Define component count for static allocation cg.add_define("ESPHOME_COMPONENT_COUNT", len(CORE.component_ids)) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 1a6d9b3a803..e6aa0e068b3 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -13,6 +13,7 @@ #define ESPHOME_PROJECT_VERSION "v2" #define ESPHOME_PROJECT_VERSION_30 "v2" #define ESPHOME_VARIANT "ESP32" +#define ESPHOME_NAME_ADD_MAC_SUFFIX #define ESPHOME_DEBUG_SCHEDULER #define ESPHOME_DEBUG_API