From 4714b77f45b8de4c66c224d67e4230cc56fa550c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 16 Sep 2026 03:37:28 -0500 Subject: [PATCH] [core] Construct App without value initialization (#19109) --- esphome/core/application.h | 2 +- esphome/core/config.py | 5 +++-- tests/unit_tests/core/test_config.py | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/esphome/core/application.h b/esphome/core/application.h index a12cdc4ac88..f1cf6fcca02 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -528,7 +528,7 @@ class Application { // 1-byte members (grouped together to minimize padding) uint8_t app_state_{0}; - bool name_add_mac_suffix_; + bool name_add_mac_suffix_{false}; bool in_loop_{false}; volatile bool has_pending_enable_loop_requests_{false}; diff --git a/esphome/core/config.py b/esphome/core/config.py index 67a7b5210ee..8a4eb0fc379 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -717,9 +717,10 @@ async def to_code(config: ConfigType) -> None: cg.add_global(cg.RawExpression("using std::min")) cg.add_global(cg.RawExpression("using std::max")) - # Construct App via placement new — see application.cpp for storage details + # Construct App via placement new — see application.cpp for storage details. + # No parens: `Application()` would zero-fill storage that is already zero. cg.add_global(cg.RawStatement("#include ")) - cg.add(cg.RawExpression("new (&App) Application()")) + cg.add(cg.RawExpression("new (&App) Application")) name = config[CONF_NAME] friendly_name = config[CONF_FRIENDLY_NAME] name_add_mac_suffix = config[CONF_NAME_ADD_MAC_SUFFIX] diff --git a/tests/unit_tests/core/test_config.py b/tests/unit_tests/core/test_config.py index 8ab3ad5d153..07cff003cdd 100644 --- a/tests/unit_tests/core/test_config.py +++ b/tests/unit_tests/core/test_config.py @@ -175,6 +175,27 @@ async def test_core_area_recorded_at_config_load( assert CORE.area == expected_area +@pytest.mark.asyncio +async def test_app_is_default_initialized( + yaml_file: Callable[[str], Path], +) -> None: + """App is constructed with `new (&App) Application`, no parentheses. + + `Application()` would value-initialize and memset the whole object into + storage that is already zero.""" + result = load_config_from_fixture(yaml_file, "valid_area_device.yaml", FIXTURES_DIR) + assert result is not None + + with patch("esphome.core.config.cg") as mock_cg: + mock_cg.RawStatement.side_effect = lambda *args, **kwargs: MagicMock() + mock_cg.RawExpression.side_effect = lambda *args, **kwargs: MagicMock() + await config.to_code(result[CONF_ESPHOME]) + + raw_expressions = [c.args[0] for c in mock_cg.RawExpression.call_args_list] + assert "new (&App) Application" in raw_expressions + assert "new (&App) Application()" not in raw_expressions + + def test_config_load_without_area_clears_stale_core_area( yaml_file: Callable[[str], Path], ) -> None: