https://github.com/atharvaajmera updated https://github.com/llvm/llvm-project/pull/227716
>From f9f5bc04354611fcc3ad2001e3af5100151c95d0 Mon Sep 17 00:00:00 2001 From: atharvaajmera <[email protected]> Date: Wed, 30 Sep 2026 19:06:41 +0530 Subject: [PATCH 1/2] [clang][Sema] Fix over-read when scanf format ends with field width ParseAmount advances I to E when digits run to the end of the string but returns NotSpecified, so ParseScanfSpecifier skipped its I == E incomplete-specifier check for %*<width> at end-of-string. The parser then read *E out-of-bounds via ParseLengthModifier, the NUL test, and the conversion switch, producing bogus diagnostics and asserting in StringLiteral::getLocationOfByte for concatenated literals. Check I == E unconditionally after the field width, matching printf and ParseArgPosition handling. Fixes #227616 --- clang/docs/ReleaseNotes.md | 5 ++++- clang/lib/AST/ScanfFormatString.cpp | 10 +++++----- clang/test/Sema/format-strings-scanf.c | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3c6acf353f93f6..7296bf81c8f3ce 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -561,7 +561,10 @@ features cannot lower the translation-unit ABI level; - Fixed a bug where a bit-field accessed as the result of a statement expression (e.g. `({ s.b; })`) was not subject to integer promotion, unlike an ordinary bit-field access. (#GH221542) - +- Fixed an assertion failure and bogus warnings when a `scanf` format string + ends with a field width such as `%*2`; it is now diagnosed as an incomplete + format specifier instead of reading past the end of the literal. (#GH227616) + #### Bug Fixes to Compiler Builtins - Fixed a crash when classifying a call to a builtin with dependent arguments, diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 5e1622e95277be..2030ee60251f7a 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -131,12 +131,12 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) { assert(Amt.getHowSpecified() == OptionalAmount::Constant); FS.setFieldWidth(Amt); + } - if (I == E) { - // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); - return true; - } + if (I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return true; } // Look for the length modifier. diff --git a/clang/test/Sema/format-strings-scanf.c b/clang/test/Sema/format-strings-scanf.c index 941e3f7513bd6b..495c5b148d66c5 100644 --- a/clang/test/Sema/format-strings-scanf.c +++ b/clang/test/Sema/format-strings-scanf.c @@ -306,3 +306,22 @@ void test_promotion(void) { scanf("%hhd", &c); // Pedantic warning? scanf("%hhd", vp); // expected-warning{{format specifies type 'char *' but the argument has type 'void *'}} } + +// GH227616: field width running to end-of-string must be diagnosed as +// incomplete, not over-read past the literal. +void test_incomplete_scanf_width(FILE *f, int *i, char *buf) { + fscanf(f, "%*2"); // expected-warning{{incomplete format specifier}} + fscanf(f, "%*12"); // expected-warning{{incomplete format specifier}} + fscanf(f, "a" "%*2", 0); // expected-warning{{incomplete format specifier}} + scanf("%*2"); // expected-warning{{incomplete format specifier}} + scanf("%2"); // expected-warning{{incomplete format specifier}} + scanf("%*"); // expected-warning{{incomplete format specifier}} + scanf("a" "%2"); // expected-warning{{incomplete format specifier}} + + // Valid uses with a field width must not warn. + scanf("%2d", i); // no-warning + scanf("%*2d"); // no-warning + fscanf(f, "%*2d"); // no-warning + fscanf(f, "a" "%*2d"); // no-warning + sscanf(buf, "%*12d"); // no-warning +} >From dfac2099b8c6d397aea21605919a335a8bedb434 Mon Sep 17 00:00:00 2001 From: atharvaajmera <[email protected]> Date: Thu, 1 Oct 2026 22:46:01 +0530 Subject: [PATCH 2/2] Address review nit: move comment before if --- clang/lib/AST/ScanfFormatString.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 2030ee60251f7a..6f2627c5390709 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -133,8 +133,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, FS.setFieldWidth(Amt); } + // No more characters left. if (I == E) { - // No more characters left? H.HandleIncompleteSpecifier(Start, E - Start); return true; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
