From 6dd555487b529f61d0adc90d817ff8b7c3d372e8 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 12 Feb 2026 10:35:24 -0600 Subject: [PATCH] Fix off-by-one in get_descriptor_string loop bound bLength includes the 2-byte descriptor header, so the character count is (bLength - 2) / 2, not bLength / 2. The old loop read one wData entry past the actual string data. Also guard bLength < 2. --- esphome/components/usb_host/usb_host_client.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/esphome/components/usb_host/usb_host_client.cpp b/esphome/components/usb_host/usb_host_client.cpp index 8b00ace4e32..e837f21a9ab 100644 --- a/esphome/components/usb_host/usb_host_client.cpp +++ b/esphome/components/usb_host/usb_host_client.cpp @@ -143,16 +143,17 @@ static void usb_client_print_config_descriptor(const usb_config_desc_t *cfg_desc } while (next_desc != NULL); } #endif -// USB string descriptors: bLength (uint8_t, max 255) includes 2-byte header. -// Loop iterates bLength/2 times (max 127), each writing at most 1 ASCII char, plus null terminator. +// USB string descriptors: bLength (uint8_t, max 255) includes 2-byte header (bLength + bDescriptorType). +// Character count = (bLength - 2) / 2, max 126 chars + null terminator. static constexpr size_t DESC_STRING_BUF_SIZE = 128; static const char *get_descriptor_string(const usb_str_desc_t *desc, std::span buffer) { - if (desc == nullptr) + if (desc == nullptr || desc->bLength < 2) return "(unspecified)"; + int char_count = (desc->bLength - 2) / 2; char *p = buffer.data(); char *end = p + buffer.size() - 1; - for (int i = 0; i != desc->bLength / 2 && p < end; i++) { + for (int i = 0; i != char_count && p < end; i++) { auto c = desc->wData[i]; if (c < 0x100) *p++ = static_cast(c);