From 2ec79afd89932f0d5a9c44050e7b6dc08ff51699 Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Fri, 11 Nov 2022 22:45:08 +0800 Subject: [PATCH] [Sema] check InitListExpr format strings like {"foo"} Adds InitListExpr case in format string checks. e.g. int sprintf(char *__restrict, const char * __restrict, ...); int foo() { char data[100]; constexpr const char* fmt2{"%d"}; // no-warning sprintf(data, fmt2, 123); } Fixes: https://github.com/llvm/llvm-project/issues/58900 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D137839 --- clang/lib/Sema/SemaChecking.cpp | 9 +++++++++ clang/test/SemaCXX/format-strings.cpp | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 75bd0ef..7b6279b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8585,6 +8585,15 @@ tryAgain: return SLCT_UncheckedLiteral; switch (E->getStmtClass()) { + case Stmt::InitListExprClass: + // Handle expressions like {"foobar"}. + if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) { + return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg, + Type, CallType, /*InFunctionCall*/ false, + CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); + } + return SLCT_NotALiteral; case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // The expression is a literal if both sub-expressions were, and it was diff --git a/clang/test/SemaCXX/format-strings.cpp b/clang/test/SemaCXX/format-strings.cpp index 2378eea..2def986 100644 --- a/clang/test/SemaCXX/format-strings.cpp +++ b/clang/test/SemaCXX/format-strings.cpp @@ -203,6 +203,12 @@ void f() { printf(string_linebreak(), 1, 2, 3, 4); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}} printf(not_literal(), 1, 2, 3, 4); // expected-warning {{format string is not a string literal}} printf(wrap_constexpr(), 1, 2); // expected-warning {{format specifies type 'char *' but the argument has type 'int'}} + + constexpr const char *fmt {"%d%d"}; + printf(fmt, 1, 1); // no-warning + + constexpr const char *fmt2 {"%d"}; // expected-note{{format string is defined here}} + printf(fmt2, "oops"); // expected-warning{{format specifies type 'int' but the argument has type}} } -- 2.7.4