[clang] [clang] Constant-evaluate format strings as last resort (PR #135864)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 18 00:13:02 PDT 2025
================
@@ -6331,26 +6321,79 @@ static StringLiteralCheckType checkFormatStringExpr(
}
}
- return SLCT_NotALiteral;
+ // try to constant-evaluate the string
+ break;
}
default:
+ // try to constant-evaluate the string
+ break;
+ }
+
+ const StringLiteral *FakeLiteral = nullptr;
+ switch (constEvalStringAsLiteral(S, E, FakeLiteral)) {
+ case SLCER_NotEvaluated:
return SLCT_NotALiteral;
+
+ case SLCER_NotNullTerminated:
+ S.Diag(Args[format_idx]->getBeginLoc(),
+ diag::warn_printf_format_string_not_null_terminated)
+ << Args[format_idx]->getSourceRange();
+ if (!InFunctionCall)
+ S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
+ // Stop checking, as this might just mean we're missing a chunk of the
+ // format string and there would be other spurious format issues.
+ return SLCT_UncheckedLiteral;
+
+ case SLCER_Evaluated:
+ InFunctionCall = false;
+ E = FakeLiteral;
+ goto tryAgain;
}
}
-// If this expression can be evaluated at compile-time,
-// check if the result is a StringLiteral and return it
-// otherwise return nullptr
-static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
- const Expr *E) {
+static StringLiteralConstEvalResult
+constEvalStringAsLiteral(Sema &S, const Expr *E, const StringLiteral *&SL) {
+ // As a last resort, try to constant-evaluate the format string. If it
+ // evaluates to a string literal in the first place, we can point to that
+ // string literal in source and use that.
Expr::EvalResult Result;
- if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
+ if (E->EvaluateAsRValue(Result, S.Context) && Result.Val.isLValue()) {
const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
- if (isa_and_nonnull<StringLiteral>(LVE))
- return LVE;
+ if (auto *BaseSL = dyn_cast_or_null<StringLiteral>(LVE)) {
+ SL = BaseSL;
+ return SLCER_Evaluated;
+ }
}
- return nullptr;
+
+ // Otherwise, try to evaluate the expression as a string constant.
+ std::string FormatString;
+ if (!E->tryEvaluateString(S.Context, FormatString)) {
+ return FormatString.empty() ? SLCER_NotEvaluated : SLCER_NotNullTerminated;
+ }
+
+ std::unique_ptr<llvm::MemoryBuffer> MemBuf;
+ {
+ llvm::SmallString<80> EscapedString;
+ {
+ llvm::raw_svector_ostream OS(EscapedString);
+ OS << '"';
+ OS.write_escaped(FormatString);
----------------
cor3ntin wrote:
You should not need to do any escaping here, the diagnostics engine should take care of that for you.
You probably want tests for that.
https://github.com/llvm/llvm-project/pull/135864
More information about the cfe-commits
mailing list