mirror of
https://github.com/esphome/esphome.git
synced 2026-09-15 17:18:40 +00:00
[api] Gate 48-bit MAC range check behind ESPHOME_DEBUG_API
Copilot flagged that encode_varint_raw_48bit/calc_uint64_48bit_force
would silently truncate for uint64 values >= 2^48. In practice the
(mac_address) option is only applied to fields populated by the BLE
stack, which always fits in 48 bits -- so the runtime upper-bound
check added in ba362a7c95 regressed CodSpeed by up to 8.7pp on
CalculateSize_BLERawAdvs12 for a scenario that can't happen.
Move the value-fits-in-48-bits check to a debug assert guarded by
ESPHOME_DEBUG_API, and express 48 via MAC_ADDRESS_SIZE * 8 so the
threshold tracks the existing MAC size constant. Release builds are
back to the original fast path; debug builds catch misuse.
This commit is contained in:
@@ -344,13 +344,17 @@ class ProtoEncode {
|
||||
}
|
||||
/// Encode a 48-bit MAC address (stored in a uint64) as varint.
|
||||
/// Real MAC addresses occupy the full 48 bits (OUI in upper 24), so the
|
||||
/// fast path -- any non-zero bit in bits [42..47] with value fitting in
|
||||
/// 48 bits -- emits exactly 7 bytes with no per-byte branch. Values outside
|
||||
/// [1<<42, 1<<48) fall back to the general encoder to preserve correctness
|
||||
/// if this helper is ever misapplied to a non-MAC uint64.
|
||||
/// fast path -- any non-zero bit in the top 6 of 48 -- emits exactly 7 bytes
|
||||
/// with no per-byte branch. Falls back to the general loop otherwise.
|
||||
/// Caller must guarantee value fits in 48 bits (checked in debug builds).
|
||||
static inline void ESPHOME_ALWAYS_INLINE encode_varint_raw_48bit(uint8_t *__restrict__ &pos PROTO_ENCODE_DEBUG_PARAM,
|
||||
uint64_t value) {
|
||||
if (value >= (1ULL << 42) && value < (1ULL << 48)) [[likely]] {
|
||||
#ifdef ESPHOME_DEBUG_API
|
||||
assert(value < (1ULL << (MAC_ADDRESS_SIZE * 8)) && "encode_varint_raw_48bit: value exceeds 48 bits");
|
||||
#endif
|
||||
// 7-byte varint holds 49 bits (7 * 7), so a 48-bit value needs all 7 bytes
|
||||
// whenever bit 42 or higher is set (i.e. value >= 1 << (48 - 6)).
|
||||
if (value >= (1ULL << (MAC_ADDRESS_SIZE * 8 - 6))) [[likely]] {
|
||||
PROTO_ENCODE_CHECK_BOUNDS(pos, 7);
|
||||
pos[0] = static_cast<uint8_t>(value | 0x80);
|
||||
pos[1] = static_cast<uint8_t>((value >> 7) | 0x80);
|
||||
@@ -840,12 +844,12 @@ class ProtoSize {
|
||||
return field_id_size + varint(value);
|
||||
}
|
||||
/// 48-bit MAC address variant: matches encode_varint_raw_48bit's fast path.
|
||||
/// When value is in [1<<42, 1<<48) the encoded varint is 7 bytes; values
|
||||
/// outside that range fall back to the general size calculation so the
|
||||
/// result stays correct if this helper is ever misapplied.
|
||||
/// When any of the top 6 of 48 bits is set the encoded varint is 7 bytes;
|
||||
/// otherwise fall back to the general size calculation.
|
||||
/// Caller must guarantee value fits in 48 bits (encoder asserts in debug).
|
||||
static constexpr inline uint32_t ESPHOME_ALWAYS_INLINE calc_uint64_48bit_force(uint32_t field_id_size,
|
||||
uint64_t value) {
|
||||
return field_id_size + ((value >= (1ULL << 42) && value < (1ULL << 48)) ? 7 : varint(value));
|
||||
return field_id_size + (value >= (1ULL << (MAC_ADDRESS_SIZE * 8 - 6)) ? 7 : varint(value));
|
||||
}
|
||||
static constexpr uint32_t calc_length(uint32_t field_id_size, size_t len) {
|
||||
return len ? field_id_size + varint(static_cast<uint32_t>(len)) + static_cast<uint32_t>(len) : 0;
|
||||
|
||||
Reference in New Issue
Block a user