[clang] [clang] Constant-evaluate format strings as last resort (PR #135864)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 12 03:31:14 PDT 2025
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>,
=?utf-8?q?Félix?= Cloutier <fcloutier at apple.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/135864 at github.com>
================
@@ -17971,46 +18006,117 @@ static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result,
S->getCharByteWidth() == 1 &&
// FIXME: Add fast-path for wchar_t too.
Info.Ctx.hasSameUnqualifiedType(CharTy, Info.Ctx.CharTy)) {
- Str = Str.substr(Off);
-
- StringRef::size_type Pos = Str.find(0);
- if (Pos != StringRef::npos)
- Str = Str.substr(0, Pos);
-
- Result = Str.size();
- if (StringResult)
- *StringResult = Str;
- return true;
+ Offset = static_cast<uint64_t>(Off);
+ return S;
}
-
- // Fall through to slow path.
}
+ return nullptr;
+}
- // Slow path: scan the bytes of the string looking for the terminating 0.
- for (uint64_t Strlen = 0; /**/; ++Strlen) {
+template <typename CharAction>
+static bool IterateStringLValue(EvalInfo &Info, const Expr *E, QualType CharTy,
+ LValue &String, CharAction &&Action) {
+ while (true) {
APValue Char;
if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) ||
!Char.isInt())
return false;
- if (!Char.getInt()) {
- Result = Strlen;
+ if (!Action(Char.getInt().getExtValue()))
return true;
- } else if (StringResult)
- StringResult->push_back(Char.getInt().getExtValue());
if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1))
return false;
}
}
-std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const {
+static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result,
+ EvalInfo &Info) {
+ LValue String;
+ QualType CharTy;
+ if (!EvaluateStringAsLValue(Info, E, CharTy, String))
+ return false;
+
+ // Fast path: if it's a string literal, search the string value.
+ uint64_t Off;
+ if (const auto *S = StringLValueIsLiteral(Info, String, CharTy, Off)) {
+ StringRef Str = S->getBytes().substr(Off);
+
+ StringRef::size_type Pos = Str.find(0);
+ if (Pos != StringRef::npos)
+ Str = Str.substr(0, Pos);
+
+ Result = Str.size();
+ return true;
+ }
+
+ // Slow path: scan the bytes of the string looking for the terminating 0.
+ Result = 0;
+ return IterateStringLValue(Info, E, CharTy, String, [&](int Char) {
+ if (Char) {
+ Result++;
+ return true;
+ } else
+ return false;
+ });
+}
+
+Expr::StringEvalResult::StringEvalResult(const StringLiteral *SL,
+ uint64_t Offset)
+ : SL(SL), Offset(Offset) {}
+
+Expr::StringEvalResult::StringEvalResult(std::string Contents)
+ : Storage(std::move(Contents)), SL(nullptr), Offset(0) {}
+
+llvm::StringRef Expr::StringEvalResult::getString() const {
+ return SL ? SL->getBytes().substr(Offset) : Storage;
+}
+
+bool Expr::StringEvalResult::getStringLiteral(const StringLiteral *&SL,
+ uint64_t &Offset) const {
+ if (this->SL) {
+ SL = this->SL;
+ Offset = this->Offset;
+ return true;
+ }
+ return false;
+}
+
+std::optional<Expr::StringEvalResult>
+Expr::tryEvaluateString(ASTContext &Ctx, bool *NullTerminated,
+ bool InConstantContext) const {
+ if (NullTerminated)
+ *NullTerminated = false;
----------------
cor3ntin wrote:
Can we put that in StringEvalResult instead?
https://github.com/llvm/llvm-project/pull/135864
More information about the cfe-commits
mailing list