diff --git a/esphome/code_scan.py b/esphome/code_scan.py index eede0f7747a..4d0342f872c 100644 --- a/esphome/code_scan.py +++ b/esphome/code_scan.py @@ -23,9 +23,10 @@ from esphome.types import ConfigType _LOGGER = logging.getLogger(__name__) # The string literal handed to a scanf family call as its format: an optional -# first argument (sscanf/fscanf, possibly a literal itself) then the literal. +# first argument (sscanf/fscanf; a literal or a call with its own commas is +# fine) then the literal. _SCANF_FORMAT_RE = re.compile( - r'scanf\s*\((?:(?:"(?:[^"\\]|\\.)*"|[^,;"])*,)?\s*"((?:[^"\\]|\\.)*)"' + r'scanf\s*\((?:(?:"(?:[^"\\]|\\.)*"|\([^()]*\)|[^,;"()])*,)?\s*"((?:[^"\\]|\\.)*)"' ) # Standard scanf float conversions %f %F %e %E %g %G %a %A with optional # suppression, width and length; also the invalid %.2f users write by analogy diff --git a/tests/unit_tests/test_code_scan.py b/tests/unit_tests/test_code_scan.py index fa8efdf14a0..6ba602d6364 100644 --- a/tests/unit_tests/test_code_scan.py +++ b/tests/unit_tests/test_code_scan.py @@ -43,6 +43,9 @@ from esphome.types import ConfigType # Escaped quotes, nested calls, a ')' inside the format, an unterminated call ('sscanf(buf, "\\"%f\\"", &v)', True), ('sscanf(f(x), "%f", &v)', True), + ('sscanf(s.substr(0, 2).c_str(), "%f", &v)', True), + ('sscanf(strtok(s, ","), "%f", &v)', True), + ('sscanf(strtok(s, ","), "%d", &v)', False), ('sscanf(buf, "%d)", &a); g("%f")', False), ('sscanf(buf, "%d", &a; g("%f")', False), ('sscanf(buf, "%f"', True),