9999#include "llvm/Support/Locale.h"
100100#include "llvm/Support/MathExtras.h"
101101#include "llvm/Support/SaveAndRestore.h"
102+ #include "llvm/Support/SmallVectorMemoryBuffer.h"
102103#include "llvm/Support/raw_ostream.h"
103104#include "llvm/TargetParser/RISCVTargetParser.h"
104105#include "llvm/TargetParser/Triple.h"
@@ -6047,8 +6048,14 @@ static void CheckFormatString(
60476048 llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
60486049 bool IgnoreStringsWithoutSpecifiers);
60496050
6050- static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
6051- const Expr *E);
6051+ enum StringLiteralConstEvalResult {
6052+ SLCER_NotEvaluated,
6053+ SLCER_NotNullTerminated,
6054+ SLCER_Evaluated,
6055+ };
6056+
6057+ static StringLiteralConstEvalResult
6058+ constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL);
60526059
60536060// Determine if an expression is a string literal or constant string.
60546061// If this function returns false on the arguments to a function expecting a
@@ -6080,14 +6087,9 @@ static StringLiteralCheckType checkFormatStringExpr(
60806087
60816088 switch (E->getStmtClass()) {
60826089 case Stmt::InitListExprClass:
6083- // Handle expressions like {"foobar"}.
6084- if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) {
6085- return checkFormatStringExpr(
6086- S, ReferenceFormatString, SLE, Args, APK, format_idx, firstDataArg,
6087- Type, CallType, /*InFunctionCall*/ false, CheckedVarArgs,
6088- UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers);
6089- }
6090- return SLCT_NotALiteral;
6090+ // try to constant-evaluate the string
6091+ break;
6092+
60916093 case Stmt::BinaryConditionalOperatorClass:
60926094 case Stmt::ConditionalOperatorClass: {
60936095 // The expression is a literal if both sub-expressions were, and it was
@@ -6178,10 +6180,9 @@ static StringLiteralCheckType checkFormatStringExpr(
61786180 if (InitList->isStringLiteralInit())
61796181 Init = InitList->getInit(0)->IgnoreParenImpCasts();
61806182 }
6181- return checkFormatStringExpr(
6182- S, ReferenceFormatString, Init, Args, APK, format_idx,
6183- firstDataArg, Type, CallType,
6184- /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg, Offset);
6183+ InFunctionCall = false;
6184+ E = Init;
6185+ goto tryAgain;
61856186 }
61866187 }
61876188
@@ -6254,11 +6255,9 @@ static StringLiteralCheckType checkFormatStringExpr(
62546255 }
62556256 return SLCT_UncheckedLiteral;
62566257 }
6257- return checkFormatStringExpr(
6258- S, ReferenceFormatString, PVFormatMatches->getFormatString(),
6259- Args, APK, format_idx, firstDataArg, Type, CallType,
6260- /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg,
6261- Offset, IgnoreStringsWithoutSpecifiers);
6258+ E = PVFormatMatches->getFormatString();
6259+ InFunctionCall = false;
6260+ goto tryAgain;
62626261 }
62636262 }
62646263
@@ -6326,20 +6325,13 @@ static StringLiteralCheckType checkFormatStringExpr(
63266325 unsigned BuiltinID = FD->getBuiltinID();
63276326 if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
63286327 BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
6329- const Expr *Arg = CE->getArg(0);
6330- return checkFormatStringExpr(
6331- S, ReferenceFormatString, Arg, Args, APK, format_idx,
6332- firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs,
6333- UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers);
6328+ E = CE->getArg(0);
6329+ goto tryAgain;
63346330 }
63356331 }
63366332 }
6337- if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E))
6338- return checkFormatStringExpr(
6339- S, ReferenceFormatString, SLE, Args, APK, format_idx, firstDataArg,
6340- Type, CallType, /*InFunctionCall*/ false, CheckedVarArgs,
6341- UncoveredArg, Offset, IgnoreStringsWithoutSpecifiers);
6342- return SLCT_NotALiteral;
6333+ // try to constant-evaluate the string
6334+ break;
63436335 }
63446336 case Stmt::ObjCMessageExprClass: {
63456337 const auto *ME = cast<ObjCMessageExpr>(E);
@@ -6360,11 +6352,8 @@ static StringLiteralCheckType checkFormatStringExpr(
63606352 IgnoreStringsWithoutSpecifiers = true;
63616353 }
63626354
6363- const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
6364- return checkFormatStringExpr(
6365- S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg,
6366- Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg,
6367- Offset, IgnoreStringsWithoutSpecifiers);
6355+ E = ME->getArg(FA->getFormatIdx().getASTIndex());
6356+ goto tryAgain;
63686357 }
63696358 }
63706359
@@ -6426,7 +6415,8 @@ static StringLiteralCheckType checkFormatStringExpr(
64266415 }
64276416 }
64286417
6429- return SLCT_NotALiteral;
6418+ // try to constant-evaluate the string
6419+ break;
64306420 }
64316421 case Stmt::UnaryOperatorClass: {
64326422 const UnaryOperator *UnaOp = cast<UnaryOperator>(E);
@@ -6443,26 +6433,79 @@ static StringLiteralCheckType checkFormatStringExpr(
64436433 }
64446434 }
64456435
6446- return SLCT_NotALiteral;
6436+ // try to constant-evaluate the string
6437+ break;
64476438 }
64486439
64496440 default:
6441+ // try to constant-evaluate the string
6442+ break;
6443+ }
6444+
6445+ const StringLiteral *FakeLiteral = nullptr;
6446+ switch (constEvalStringAsLiteral(S, E, FakeLiteral)) {
6447+ case SLCER_NotEvaluated:
64506448 return SLCT_NotALiteral;
6449+
6450+ case SLCER_NotNullTerminated:
6451+ S.Diag(Args[format_idx]->getBeginLoc(),
6452+ diag::warn_printf_format_string_not_null_terminated)
6453+ << Args[format_idx]->getSourceRange();
6454+ if (!InFunctionCall)
6455+ S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
6456+ // Stop checking, as this might just mean we're missing a chunk of the
6457+ // format string and there would be other spurious format issues.
6458+ return SLCT_UncheckedLiteral;
6459+
6460+ case SLCER_Evaluated:
6461+ InFunctionCall = false;
6462+ E = FakeLiteral;
6463+ goto tryAgain;
64516464 }
64526465}
64536466
6454- // If this expression can be evaluated at compile-time,
6455- // check if the result is a StringLiteral and return it
6456- // otherwise return nullptr
6457- static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
6458- const Expr *E) {
6467+ static StringLiteralConstEvalResult
6468+ constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL) {
6469+ // As a last resort, try to constant-evaluate the format string. If it
6470+ // evaluates to a string literal in the first place, we can point to that
6471+ // string literal in source and use that.
64596472 Expr::EvalResult Result;
6460- if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
6473+ if (E->EvaluateAsRValue(Result, S. Context) && Result.Val.isLValue()) {
64616474 const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
6462- if (isa_and_nonnull<StringLiteral>(LVE))
6463- return LVE;
6475+ if (auto *BaseSL = dyn_cast_or_null<StringLiteral>(LVE)) {
6476+ SL = BaseSL;
6477+ return SLCER_Evaluated;
6478+ }
64646479 }
6465- return nullptr;
6480+
6481+ // Otherwise, try to evaluate the expression as a string constant.
6482+ std::string FormatString;
6483+ if (!E->tryEvaluateString(S.Context, FormatString)) {
6484+ return FormatString.empty() ? SLCER_NotEvaluated : SLCER_NotNullTerminated;
6485+ }
6486+
6487+ std::unique_ptr<llvm::MemoryBuffer> MemBuf;
6488+ {
6489+ llvm::SmallString<80> EscapedString;
6490+ {
6491+ llvm::raw_svector_ostream OS(EscapedString);
6492+ OS << '"';
6493+ OS.write_escaped(FormatString);
6494+ OS << '"';
6495+ }
6496+ MemBuf.reset(new llvm::SmallVectorMemoryBuffer(std::move(EscapedString),
6497+ "<scratch space>", true));
6498+ }
6499+
6500+ // Plop that string into a scratch buffer, create a string literal and then
6501+ // go with that.
6502+ auto ScratchFile = S.getSourceManager().createFileID(std::move(MemBuf));
6503+ SourceLocation Begin = S.getSourceManager().getLocForStartOfFile(ScratchFile);
6504+ QualType SLType = S.Context.getStringLiteralArrayType(S.Context.CharTy,
6505+ FormatString.length());
6506+ SL = StringLiteral::Create(S.Context, FormatString,
6507+ StringLiteralKind::Ordinary, false, SLType, Begin);
6508+ return SLCER_Evaluated;
64666509}
64676510
64686511StringRef Sema::GetFormatStringTypeName(FormatStringType FST) {
@@ -7086,10 +7129,11 @@ void CheckFormatHandler::EmitFormatDiagnostic(
70867129 S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
70877130 << ArgumentExpr->getSourceRange();
70887131
7089- const Sema::SemaDiagnosticBuilder &Note =
7090- S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
7091- diag::note_format_string_defined);
7092-
7132+ SourceLocation DiagLoc = IsStringLocation ? Loc : StringRange.getBegin();
7133+ unsigned DiagID = S.getSourceManager().isWrittenInScratchSpace(DiagLoc)
7134+ ? diag::note_format_string_evaluated_to
7135+ : diag::note_format_string_defined;
7136+ const Sema::SemaDiagnosticBuilder &Note = S.Diag(DiagLoc, DiagID);
70937137 Note << StringRange;
70947138 Note << FixIt;
70957139 }
0 commit comments