From 4befd86a962f3302f2259f304624f8c73b2e520b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 14 Jan 2026 15:56:32 -1000 Subject: [PATCH 1/3] review --- esphome/components/cse7766/cse7766.cpp | 36 +++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index e4eb8b2c36..f0d1f91398 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -2,6 +2,7 @@ #include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#include namespace esphome { namespace cse7766 { @@ -9,6 +10,25 @@ namespace cse7766 { static const char *const TAG = "cse7766"; static constexpr size_t CSE7766_RAW_DATA_SIZE = 24; +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE +/// Safely append formatted string to buffer, returning new position (capped at size). +/// Handles negative return values from snprintf (encoding errors). +__attribute__((format(printf, 4, 5))) static size_t buf_append_(char *buf, size_t size, size_t pos, const char *fmt, + ...) { + if (pos >= size) { + return size; + } + va_list args; + va_start(args, fmt); + int written = vsnprintf(buf + pos, size - pos, fmt, args); + va_end(args); + if (written < 0) { + return pos; // encoding error + } + return std::min(pos + static_cast(written), size); +} +#endif + void CSE7766Component::loop() { const uint32_t now = App.get_loop_component_start_time(); if (now - this->last_transmission_ >= 500) { @@ -207,23 +227,21 @@ void CSE7766Component::parse_data_() { #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE { - // Buffer: 7 + 14 + 31 + 14 + 24 = 90 chars max + null, rounded to 96 + // Buffer: 7 + 14 + 31 + 14 + 24 = 90 chars max + null, rounded to 96. + // Float sizes assume typical sensor values (voltage ~220V, current <10A, power <3000W). char buf[96]; - int pos = snprintf(buf, sizeof(buf), "Parsed:"); // max 7: "Parsed:" + size_t pos = buf_append_(buf, sizeof(buf), 0, "Parsed:"); if (have_voltage) { - pos += snprintf(buf + pos, sizeof(buf) - pos, " V=%.4fV", voltage); // max 14: " V="(3) + float(10) + "V"(1) + pos = buf_append_(buf, sizeof(buf), pos, " V=%.4fV", voltage); } if (have_current) { - pos += - snprintf(buf + pos, sizeof(buf) - pos, " I=%.4fmA (~%.4fmA)", current * 1000.0f, - calculated_current * 1000.0f); // max 31: " I="(3) + float(10) + "mA (~"(5) + float(10) + "mA)"(3) + pos = buf_append_(buf, sizeof(buf), pos, " I=%.4fmA (~%.4fmA)", current * 1000.0f, calculated_current * 1000.0f); } if (have_power) { - pos += snprintf(buf + pos, sizeof(buf) - pos, " P=%.4fW", power); // max 14: " P="(3) + float(10) + "W"(1) + pos = buf_append_(buf, sizeof(buf), pos, " P=%.4fW", power); } if (energy != 0.0f) { - snprintf(buf + pos, sizeof(buf) - pos, " E=%.4fkWh (%u)", energy, - cf_pulses); // max 24: " E="(3) + float(10) + "kWh ("(5) + uint16(5) + ")"(1) + buf_append_(buf, sizeof(buf), pos, " E=%.4fkWh (%u)", energy, cf_pulses); } ESP_LOGVV(TAG, "%s", buf); } From 0b676c0daa4bc17dd8c683a9da5956f3fd42be5a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 14 Jan 2026 16:02:42 -1000 Subject: [PATCH 2/3] review --- esphome/components/cse7766/cse7766.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index f0d1f91398..6a61e726b9 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -227,9 +227,9 @@ void CSE7766Component::parse_data_() { #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE { - // Buffer: 7 + 14 + 31 + 14 + 24 = 90 chars max + null, rounded to 96. - // Float sizes assume typical sensor values (voltage ~220V, current <10A, power <3000W). - char buf[96]; + // Buffer: 7 + 15 + 33 + 15 + 25 = 95 chars max + null, rounded to 128 for safety margin. + // Float sizes with %.4f can be up to 11 chars for large values (e.g., 999999.9999). + char buf[128]; size_t pos = buf_append_(buf, sizeof(buf), 0, "Parsed:"); if (have_voltage) { pos = buf_append_(buf, sizeof(buf), pos, " V=%.4fV", voltage); From d49c06df35e739b002d67589db874cae5cd25659 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 14 Jan 2026 16:04:22 -1000 Subject: [PATCH 3/3] Increase buffer to 128 bytes and improve docstrings --- esphome/components/cse7766/cse7766.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/esphome/components/cse7766/cse7766.cpp b/esphome/components/cse7766/cse7766.cpp index 6a61e726b9..3628958c89 100644 --- a/esphome/components/cse7766/cse7766.cpp +++ b/esphome/components/cse7766/cse7766.cpp @@ -11,8 +11,15 @@ static const char *const TAG = "cse7766"; static constexpr size_t CSE7766_RAW_DATA_SIZE = 24; #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE -/// Safely append formatted string to buffer, returning new position (capped at size). -/// Handles negative return values from snprintf (encoding errors). +/// @brief Safely append formatted string to buffer. +/// @param buf Destination buffer (must be non-null) +/// @param size Total buffer size in bytes +/// @param pos Current write position (0 to size-1 for valid positions, size means full) +/// @param fmt printf-style format string +/// @return New write position: pos + chars_written, capped at size when buffer is full. +/// Returns size (not size-1) when full because vsnprintf already wrote the null +/// terminator at buf[size-1]. Returning size signals "no room for more content". +/// On encoding error, returns pos unchanged (no write occurred). __attribute__((format(printf, 4, 5))) static size_t buf_append_(char *buf, size_t size, size_t pos, const char *fmt, ...) { if (pos >= size) {