From bd78b546c8e14667f44298d35d8ff228b6b31ee0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 18 Feb 2026 08:26:04 -0600 Subject: [PATCH] fix --- esphome/components/api/proto.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/esphome/components/api/proto.h b/esphome/components/api/proto.h index ec695b44f0..bb4abdfc49 100644 --- a/esphome/components/api/proto.h +++ b/esphome/components/api/proto.h @@ -108,12 +108,17 @@ class ProtoVarInt { #ifdef ESPHOME_DEBUG_API assert(consumed != nullptr); #endif - // 32-bit phase: bytes 0-4 cover all uint32 varint values - // Byte 4 shift (28) may truncate upper 3 bits in uint32, but those are - // always zero for valid uint32 values; parse_wide re-processes byte 4 - // with full 64-bit arithmetic when the varint continues past byte 4. + // 32-bit phase: shifts 0, 7, 14, 21 are native on 32-bit platforms. + // Without USE_API_VARINT64: also cover byte 4 (shift 28) — the uint32_t + // shift truncates upper bits but those are always zero for valid uint32 values. + // With USE_API_VARINT64: stop at byte 3 so parse_wide handles byte 4+ + // with full 64-bit arithmetic (avoids truncating values > UINT32_MAX). uint32_t result32 = 0; +#ifdef USE_API_VARINT64 + uint32_t limit = std::min(len, uint32_t(4)); +#else uint32_t limit = std::min(len, uint32_t(5)); +#endif for (uint32_t i = 0; i < limit; i++) { uint8_t val = buffer[i]; result32 |= uint32_t(val & 0x7F) << (i * 7); @@ -122,7 +127,7 @@ class ProtoVarInt { return ProtoVarInt(result32); } } - // 64-bit phase for values > 32 bits (BLE addresses etc.) + // 64-bit phase for remaining bytes (BLE addresses etc.) #ifdef USE_API_VARINT64 return parse_wide(buffer, len, consumed, result32); #else