From ed6c54efcb00e32a7ce5127a74471ea285da26a5 Mon Sep 17 00:00:00 2001 From: clydebarrow <2366188+clydebarrow@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:19:04 +1100 Subject: [PATCH] [uart] Limit a received packet to the receive buffer The receive buffer is sized by code generation to max_packet_size, but set_max_packet_size() can raise the limit afterwards, and the received bytes would then overflow the buffer. The link now takes the buffer as a span and stops at its size too. Co-Authored-By: Claude Opus 5.5 --- .../uart/packet_interface/uart_packet_interface.cpp | 4 ++-- .../uart/packet_interface/uart_packet_interface.h | 9 ++++++--- tests/components/uart/uart_packet_interface.cpp | 13 +++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/esphome/components/uart/packet_interface/uart_packet_interface.cpp b/esphome/components/uart/packet_interface/uart_packet_interface.cpp index 9669df530b1..ff74b2d1a17 100644 --- a/esphome/components/uart/packet_interface/uart_packet_interface.cpp +++ b/esphome/components/uart/packet_interface/uart_packet_interface.cpp @@ -24,7 +24,7 @@ void UartPacketInterface::loop() { if (byte == FLAG_BYTE) { // A flag that ends a frame also starts the next, so an unfinished frame cannot hide the one after it if (this->rx_started_ && this->rx_length_ != 0) - this->on_receive_from_interface_(PacketBuffer(this->rx_buffer_, this->rx_length_), {}); + this->on_receive_from_interface_(PacketBuffer(this->rx_buffer_.data(), this->rx_length_), {}); this->rx_started_ = true; this->rx_length_ = 0; this->rx_control_ = false; @@ -40,7 +40,7 @@ void UartPacketInterface::loop() { byte ^= ESCAPE_XOR; this->rx_control_ = false; } - if (this->rx_length_ >= this->max_packet_size_) { + if (this->rx_length_ >= this->max_packet_size_ || this->rx_length_ >= this->rx_buffer_.size()) { ESP_LOGD(TAG, "Packet too large, discarding"); this->rx_started_ = false; this->rx_length_ = 0; diff --git a/esphome/components/uart/packet_interface/uart_packet_interface.h b/esphome/components/uart/packet_interface/uart_packet_interface.h index ce089dbcdfe..9420eaa1747 100644 --- a/esphome/components/uart/packet_interface/uart_packet_interface.h +++ b/esphome/components/uart/packet_interface/uart_packet_interface.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "esphome/components/packet_interface/packet_interface.h" #include "esphome/components/uart/uart.h" @@ -14,15 +16,16 @@ namespace esphome::uart { */ class UartPacketInterface : public packet_interface::PacketInterface, public UARTDevice { public: - /// @param rx_buffer Holds max_packet_size bytes of unescaped received data; must outlive the link - explicit UartPacketInterface(uint8_t *rx_buffer) : rx_buffer_(rx_buffer) {} + /// @param rx_buffer Holds the unescaped data being received, sized by code generation to max_packet_size; must + /// outlive the link. A larger max_packet_size set later is limited to it. + explicit UartPacketInterface(std::span rx_buffer) : rx_buffer_(rx_buffer) {} void loop() override; bool send_to_interface(const packet_interface::PacketBuffer &data, const packet_interface::PacketMetaData &meta_data) override; protected: - uint8_t *const rx_buffer_; + const std::span rx_buffer_; size_t rx_length_{0}; bool rx_started_{}; bool rx_control_{}; diff --git a/tests/components/uart/uart_packet_interface.cpp b/tests/components/uart/uart_packet_interface.cpp index d141c6c658d..cf1db2c34a5 100644 --- a/tests/components/uart/uart_packet_interface.cpp +++ b/tests/components/uart/uart_packet_interface.cpp @@ -338,6 +338,19 @@ TEST_F(UartPacketInterfaceTest, AllByteValues) { } // Test a packet larger than max_packet_size is not sent +TEST_F(UartPacketInterfaceTest, ReceiveLimitedToBuffer) { + uint8_t small_buffer[4]{}; + UartPacketInterface interface(small_buffer); + interface.set_uart_parent(&this->uart_); + // Raised above the buffer after code generation sized it + interface.set_max_packet_size(100); + std::vector> received; + interface.add_packet_interface_listener( + [&received](const PacketBuffer &data, const PacketMetaData &) { received.push_back(to_vector(data)); }); + feed(this->uart_, interface, {0x7E, 1, 2, 3, 4, 5, 6, 0x7E, 7, 8, 0x7E}); + EXPECT_EQ(received, (std::vector>{{7, 8}})); +} + TEST_F(UartPacketInterfaceTest, OversizedPacketNotSent) { interface_.set_max_packet_size(4); std::vector data = {0x01, 0x02, 0x03, 0x04, 0x05};