From 99e0dcf5631dc13f134be47d9eee61a8cb3e9c2c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 13 Mar 2026 17:03:14 -1000 Subject: [PATCH] [esp32] Use DRAM_ATTR for format strings in IRAM log override ESP-IDF places log_format_text.c in IRAM/DRAM via linker fragment (noflash) when CONFIG_LOG_IN_IRAM=y. Our override is in a different compilation unit so string literals would default to flash. In constrained environments where flash cache is disabled, reading flash-resident format strings would fault. Move all format string constants to DRAM_ATTR to match ESP-IDF's own behavior. --- esphome/core/log.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/esphome/core/log.cpp b/esphome/core/log.cpp index f01f0053d4..098bfd8abf 100644 --- a/esphome/core/log.cpp +++ b/esphome/core/log.cpp @@ -110,9 +110,16 @@ int HOT esp_idf_log_vprintf_(const char *format, va_list args) { // NOLINT static void IRAM_ATTR __attribute__((noinline)) esp_log_format_early_(esp_log_msg_t *message) { // ESP-IDF levels: NONE=0 ERROR=1 WARN=2 INFO=3 DEBUG=4 VERBOSE=5 // Color digits: E=1(red) W=3(yellow) I=2(green) D=6(cyan) V=7(gray) - // DRAM_ATTR required since this function is in IRAM and can't access flash constants + // DRAM_ATTR required: this function is IRAM_ATTR and may be called from constrained + // environments where flash cache is disabled. All string constants must be in DRAM. + // ESP-IDF's own log_format_text.c achieves this via linker fragment (noflash), but + // our override is in a different compilation unit so we must use DRAM_ATTR explicitly. static DRAM_ATTR const char color_digit[] = {'\0', '1', '3', '2', '6', '7'}; static DRAM_ATTR const char lvl[] = {'\0', 'E', 'W', 'I', 'D', 'V'}; + static DRAM_ATTR const char fmt_header[] = "\033[0;3%cm[%c][%s:000]: "; + static DRAM_ATTR const char fmt_reset_nl[] = "\033[0m\n"; + static DRAM_ATTR const char fmt_nl[] = "\n"; + static DRAM_ATTR const char tag_fallback[] = "esp-idf"; uint8_t level = message->config.opts.log_level; #if CONFIG_LIBC_NEWLIB if (!message->config.opts.constrained_env) { @@ -120,14 +127,14 @@ static void IRAM_ATTR __attribute__((noinline)) esp_log_format_early_(esp_log_ms } #endif if (level > 0 && level < sizeof(lvl)) { - esp_log_printf(message->config, "\033[0;3%cm[%c][%s:000]: ", color_digit[level], lvl[level], - message->tag ? message->tag : "esp-idf"); + esp_log_printf(message->config, fmt_header, color_digit[level], lvl[level], + message->tag ? message->tag : tag_fallback); } esp_log_vprintf(message->config, message->format, message->args); if (level > 0 && level < sizeof(lvl)) { - esp_log_printf(message->config, "\033[0m\n"); + esp_log_printf(message->config, fmt_reset_nl); } else { - esp_log_printf(message->config, "\n"); + esp_log_printf(message->config, fmt_nl); } #if CONFIG_LIBC_NEWLIB if (!message->config.opts.constrained_env) {