Timm =?utf-8?q?Bäder?= <[email protected]> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/[email protected]>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/160118 >From 310ba0ec9d7c980d3023fcdc3e718c9155eadf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Tue, 16 Sep 2025 16:02:15 +0200 Subject: [PATCH 1/2] try evaluate string --- clang/lib/AST/ByteCode/Context.cpp | 42 ++++++++++++++++++++++++++++++ clang/lib/AST/ByteCode/Context.h | 4 +++ clang/lib/AST/ExprConstant.cpp | 8 +++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 71d0bcf61a5ff..43a4e5888506a 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -237,6 +237,48 @@ bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr, return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result); } +bool Context::evaluateString(State &Parent, const Expr *E, + std::string &Result) { + assert(Stk.empty()); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); + + auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) { + const Descriptor *FieldDesc = Ptr.getFieldDesc(); + if (!FieldDesc->isPrimitiveArray()) + return false; + + if (!Ptr.isConst()) + return false; + + unsigned N = Ptr.getNumElems(); + if (Ptr.elemSize() == 1 /* bytes */) { + const char *Chars = reinterpret_cast<const char *>(Ptr.getRawAddress()); + unsigned Length = strnlen(Chars, N); + Result.assign(Chars, Length); + return true; + } + + PrimType ElemT = FieldDesc->getPrimType(); + for (unsigned I = Ptr.getIndex(); I != N; ++I) { + INT_TYPE_SWITCH(ElemT, { + auto Elem = Ptr.elem<T>(I); + if (Elem.isZero()) + return true; + Result.push_back(static_cast<char>(Elem)); + }); + } + // We didn't find a 0 byte. + return false; + }); + + if (PtrRes.isInvalid()) { + C.cleanup(); + Stk.clear(); + return false; + } + return true; +} + bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) { assert(Stk.empty()); Compiler<EvalEmitter> C(*this, *P, Parent, Stk); diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 280a31725555f..fadedf83e68ff 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -67,6 +67,10 @@ class Context final { bool evaluateCharRange(State &Parent, const Expr *SizeExpr, const Expr *PtrExpr, std::string &Result); + /// Evaluate \param E and if it can be evaluated to a sirint literal, + /// copy the result into \param Result. + bool evaluateString(State &Parent, const Expr *E, std::string &Result); + /// Evalute \param E and if it can be evaluated to a string literal, /// run strlen() on it. bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d10e2afeb2341..2f7f290e5715c 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -18843,9 +18843,15 @@ std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const { uint64_t Result; std::string StringResult; + if (Info.EnableNewConstInterp) { + if (!Info.Ctx.getInterpContext().evaluateString(Info, this, StringResult)) + return std::nullopt; + return StringResult; + } + if (EvaluateBuiltinStrLen(this, Result, Info, &StringResult)) return StringResult; - return {}; + return std::nullopt; } template <typename T> >From 9766cad498666e53196abf60444d06603f4653d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Tue, 23 Sep 2025 09:37:46 +0200 Subject: [PATCH 2/2] Reject and test non-null terminated strings --- clang/lib/AST/ByteCode/Context.cpp | 4 ++++ clang/lib/AST/ByteCode/Context.h | 2 +- clang/test/SemaCXX/verbose-trap.cpp | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 43a4e5888506a..306f95c479d0f 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -251,9 +251,13 @@ bool Context::evaluateString(State &Parent, const Expr *E, return false; unsigned N = Ptr.getNumElems(); + if (Ptr.elemSize() == 1 /* bytes */) { const char *Chars = reinterpret_cast<const char *>(Ptr.getRawAddress()); unsigned Length = strnlen(Chars, N); + // Wasn't null terminated. + if (N == Length) + return false; Result.assign(Chars, Length); return true; } diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index fadedf83e68ff..f5fa977cbcad8 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -67,7 +67,7 @@ class Context final { bool evaluateCharRange(State &Parent, const Expr *SizeExpr, const Expr *PtrExpr, std::string &Result); - /// Evaluate \param E and if it can be evaluated to a sirint literal, + /// Evaluate \param E and if it can be evaluated to a null-terminated string, /// copy the result into \param Result. bool evaluateString(State &Parent, const Expr *E, std::string &Result); diff --git a/clang/test/SemaCXX/verbose-trap.cpp b/clang/test/SemaCXX/verbose-trap.cpp index 2503f9860d9c3..0dd090e57d016 100644 --- a/clang/test/SemaCXX/verbose-trap.cpp +++ b/clang/test/SemaCXX/verbose-trap.cpp @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify %s // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify %s -fexperimental-new-constant-interpreter + #if !__has_builtin(__builtin_verbose_trap) #error #endif @@ -45,3 +48,14 @@ void f2() { void test() { f<constCat3, constMsg3>(nullptr); } + +/// Arguments must be null terminated. +int foo() { + constexpr char K[] = {'a', 'b'}; + __builtin_verbose_trap("hehe", K); // expected-error {{argument to __builtin_verbose_trap must be a pointer to a constant string}} + __builtin_verbose_trap(K, "hehe"); //expected-error {{argument to __builtin_verbose_trap must be a pointer to a constant string}} + + constexpr char K2[] = {'a', 'b', '\0'}; + __builtin_verbose_trap("hehe", K2); + __builtin_verbose_trap(K2, "hehe"); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
