mirror of
https://github.com/esphome/esphome.git
synced 2026-10-21 13:34:12 +00:00
[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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
333090f803
commit
ed6c54efcb
@@ -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;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#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<uint8_t> 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<uint8_t> rx_buffer_;
|
||||
size_t rx_length_{0};
|
||||
bool rx_started_{};
|
||||
bool rx_control_{};
|
||||
|
||||
@@ -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<std::vector<uint8_t>> 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<std::vector<uint8_t>>{{7, 8}}));
|
||||
}
|
||||
|
||||
TEST_F(UartPacketInterfaceTest, OversizedPacketNotSent) {
|
||||
interface_.set_max_packet_size(4);
|
||||
std::vector<uint8_t> data = {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||
|
||||
Reference in New Issue
Block a user