https://github.com/hnrklssn created 
https://github.com/llvm/llvm-project/pull/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

>From bb1759ecdc423a1f5a0abcc7bd5c8ac018eb528f Mon Sep 17 00:00:00 2001
From: "Henrik G. Olsson" <h_ols...@apple.com>
Date: Wed, 23 Apr 2025 15:23:00 -0700
Subject: [PATCH] [ConstEval] Fix crash when comparing strings past the end

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
---
 clang/lib/AST/ExprConstant.cpp                   | 9 +++++++--
 clang/test/AST/ByteCode/cxx20.cpp                | 9 +++++++++
 clang/test/SemaCXX/constant-expression-cxx11.cpp | 2 ++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 80ece3c4ed7e1..262c78458b78f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2234,10 +2234,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 c35f3a5632a05..ec154517949cc 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -2199,6 +2199,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