From fc16ad806aa939f8fdc28b816ef04a8b3afed34e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 20 Jan 2026 17:53:36 -1000 Subject: [PATCH] [ci] Block sprintf/vsprintf usage, suggest snprintf alternatives (#13305) --- script/ci-custom.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/script/ci-custom.py b/script/ci-custom.py index ee2e73872c..01e197057a 100755 --- a/script/ci-custom.py +++ b/script/ci-custom.py @@ -732,6 +732,26 @@ def lint_no_heap_allocating_helpers(fname, match): ) +@lint_re_check( + # Match sprintf/vsprintf but not snprintf/vsnprintf + # [^\w] ensures we don't match the safe variants + r"[^\w](v?sprintf)\s*\(" + CPP_RE_EOL, + include=cpp_include, +) +def lint_no_sprintf(fname, match): + func = match.group(1) + safe_func = func.replace("sprintf", "snprintf") + return ( + f"{highlight(func + '()')} is not allowed in ESPHome. It has no buffer size limit " + f"and can cause buffer overflows.\n" + f"Please use one of these alternatives:\n" + f" - {highlight(safe_func + '(buf, sizeof(buf), fmt, ...)')} for general formatting\n" + f" - {highlight('buf_append_printf(buf, sizeof(buf), pos, fmt, ...)')} for " + f"offset-based formatting (also stores format strings in flash on ESP8266)\n" + f"(If strictly necessary, add `// NOLINT` to the end of the line)" + ) + + @lint_content_find_check( "ESP_LOG", include=["*.h", "*.tcc"],