Author: Henrik G. Olsson
Date: 2025-04-23T16:41:21-07:00
New Revision: 55160e6a89820f219eaa218fa02da2006213ed2c

URL: 
https://github.com/llvm/llvm-project/commit/55160e6a89820f219eaa218fa02da2006213ed2c
DIFF: 
https://github.com/llvm/llvm-project/commit/55160e6a89820f219eaa218fa02da2006213ed2c.diff

LOG: [ConstEval] Fix crash when comparing strings past the end (#137078)

When `ArePotentiallyOverlappingStringLiterals`, added in
https://github.com/llvm/llvm-project/pull/109208, compares string
literals it drops the front of the string with the greatest offset from
its base pointer. The number of characters dropped is equal to the
difference between the two strings' offsets from their base pointers.
This would trigger an assert when the resulting offset is past the end
of the object. Not only are one-past-the-end pointers legal constructs,
the compiler should not crash even when faced with illegal constructs.

rdar://149865910

Added: 
    

Modified: 
    clang/lib/AST/ExprConstant.cpp
    clang/test/AST/ByteCode/cxx20.cpp
    clang/test/SemaCXX/constant-expression-cxx11.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f598ef5929aa4..7c933f47bf7f0 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2232,10 +2232,15 @@ static bool 
ArePotentiallyOverlappingStringLiterals(const EvalInfo &Info,
   // within RHS. We don't need to look at the characters of one string that
   // would appear before the start of the other string if they were merged.
   CharUnits Offset = RHS.Offset - LHS.Offset;
-  if (Offset.isNegative())
+  if (Offset.isNegative()) {
+    if (LHSString.Bytes.size() < (size_t)-Offset.getQuantity())
+      return false;
     LHSString.Bytes = LHSString.Bytes.drop_front(-Offset.getQuantity());
-  else
+  } else {
+    if (RHSString.Bytes.size() < (size_t)Offset.getQuantity())
+      return false;
     RHSString.Bytes = RHSString.Bytes.drop_front(Offset.getQuantity());
+  }
 
   bool LHSIsLonger = LHSString.Bytes.size() > RHSString.Bytes.size();
   StringRef Longer = LHSIsLonger ? LHSString.Bytes : RHSString.Bytes;

diff  --git a/clang/test/AST/ByteCode/cxx20.cpp 
b/clang/test/AST/ByteCode/cxx20.cpp
index 42e6ae33e92e4..4c1b1592896c9 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -119,6 +119,15 @@ constexpr auto b3 = name1() == name1(); // ref-error 
{{must be initialized by a
 constexpr auto b4 = name1() == name2();
 static_assert(!b4);
 
+constexpr auto bar(const char *p) { return p + __builtin_strlen(p); }
+constexpr auto b5 = bar(p1) == p1;
+static_assert(!b5);
+constexpr auto b6 = bar(p1) == ""; // ref-error {{must be initialized by a 
constant expression}} \
+                                   // ref-note {{comparison of addresses of 
potentially overlapping literals}}
+constexpr auto b7 = bar(p1) + 1 == ""; // both-error {{must be initialized by 
a constant expression}} \
+                                       // ref-note {{comparison against 
pointer '&"test1"[6]' that points past the end of a complete object has 
unspecified value}} \
+                                       // expected-note {{comparison against 
pointer '&"test1"[6] + 1' that points past the end of a complete object has 
unspecified value}}
+
 namespace UninitializedFields {
   class A {
   public:

diff  --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp 
b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 28016da925ef9..dc8f4bf1666ee 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -2203,6 +2203,8 @@ namespace BuiltinStrlen {
   static_assert(__builtin_strlen("foo") == 3, "");
   static_assert(__builtin_strlen("foo\0quux") == 3, "");
   static_assert(__builtin_strlen("foo\0quux" + 4) == 4, "");
+  static_assert(__builtin_strlen("foo") + 1 + "foo" == "foo", ""); // 
expected-error {{static assertion expression is not an integral constant 
expression}}
+  // expected-note@-1 {{comparison against pointer '&"foo"[4]' that points 
past the end of a complete object has unspecified value}}
 
   constexpr bool check(const char *p) {
     return __builtin_strlen(p) == 3 &&


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to