From 48cc739bab55d21b6e52bf4f89104492c4f3d690 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 11 Feb 2026 08:17:51 -0600 Subject: [PATCH] Add static_assert to guard DeferredEvent size and update comments Add compile-time check that DeferredEvent has no padding, so future field additions would trigger a build error rather than silently reintroducing the unaligned access codegen issue. Update comments to reference pointer sizes instead of hardcoded "8 bytes". --- esphome/components/web_server/web_server.h | 10 ++++++---- esphome/components/web_server_idf/web_server_idf.h | 8 +++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/esphome/components/web_server/web_server.h b/esphome/components/web_server/web_server.h index b0c39f279b..ce09ebf7a9 100644 --- a/esphome/components/web_server/web_server.h +++ b/esphome/components/web_server/web_server.h @@ -112,10 +112,10 @@ class DeferredUpdateEventSource : public AsyncEventSource { /* This class holds a pointer to the source component that wants to publish a state event, and a pointer to a function that will lazily generate that event. The two pointers allow dedup in the deferred queue if multiple publishes for - the same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a - std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per - entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing - because of dedup) would take up only 0.8 kB. + the same component are backed up, and take up only two pointers of memory. The entry in the deferred queue (a + std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only two + pointers per entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors + publishing because of dedup) would take up only 0.8 kB. */ struct DeferredEvent { friend class DeferredUpdateEventSource; @@ -131,6 +131,8 @@ class DeferredUpdateEventSource : public AsyncEventSource { return (source_ == test.source_ && message_generator_ == test.message_generator_); } }; + static_assert(sizeof(DeferredEvent) == sizeof(void *) + sizeof(message_generator_t *), + "DeferredEvent should have no padding"); protected: // surface a couple methods from the base class diff --git a/esphome/components/web_server_idf/web_server_idf.h b/esphome/components/web_server_idf/web_server_idf.h index 1e6651ed03..6a409de74e 100644 --- a/esphome/components/web_server_idf/web_server_idf.h +++ b/esphome/components/web_server_idf/web_server_idf.h @@ -259,9 +259,9 @@ using message_generator_t = std::string(esphome::web_server::WebServer *, void * /* This class holds a pointer to the source component that wants to publish a state event, and a pointer to a function that will lazily generate that event. The two pointers allow dedup in the deferred queue if multiple publishes for - the same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a - std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per - entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing + the same component are backed up, and take up only two pointers of memory. The entry in the deferred queue (a + std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only two pointers + per entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing because of dedup) would take up only 0.8 kB. */ struct DeferredEvent { @@ -278,6 +278,8 @@ struct DeferredEvent { return (source_ == test.source_ && message_generator_ == test.message_generator_); } }; +static_assert(sizeof(DeferredEvent) == sizeof(void *) + sizeof(message_generator_t *), + "DeferredEvent should have no padding"); class AsyncEventSourceResponse { friend class AsyncEventSource;