[clang] c1af97d - [clang][Interp] Diagnose comparisons against one-past-end pointers

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 3 05:07:36 PDT 2024


Author: Timm Bäder
Date: 2024-07-03T14:07:28+02:00
New Revision: c1af97db1e3846db1188149afe86cee6585dfc9a

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

LOG: [clang][Interp] Diagnose comparisons against one-past-end pointers

Added: 
    

Modified: 
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Pointer.cpp
    clang/lib/AST/Interp/Pointer.h
    clang/test/AST/Interp/literals.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 328db219ca628..5d8362b4fa881 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -922,6 +922,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
     return true;
   }
 
+  // Reject comparisons to weak pointers.
   for (const auto &P : {LHS, RHS}) {
     if (P.isZero())
       continue;
@@ -934,6 +935,20 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
   }
 
   if (!Pointer::hasSameBase(LHS, RHS)) {
+    if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
+        RHS.getOffset() == 0) {
+      const SourceInfo &Loc = S.Current->getSource(OpPC);
+      S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
+          << LHS.toDiagnosticString(S.getCtx());
+      return false;
+    } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
+               LHS.getOffset() == 0) {
+      const SourceInfo &Loc = S.Current->getSource(OpPC);
+      S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
+          << RHS.toDiagnosticString(S.getCtx());
+      return false;
+    }
+
     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
     return true;
   } else {

diff  --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index 4070d0c54225d..d6603f91fb127 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -143,7 +143,7 @@ APValue Pointer::toAPValue() const {
 
   if (isDummy() || isUnknownSizeArray() || Desc->asExpr())
     return APValue(Base, CharUnits::Zero(), Path,
-                   /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
+                   /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
 
   // TODO: compute the offset into the object.
   CharUnits Offset = CharUnits::Zero();
@@ -181,7 +181,8 @@ APValue Pointer::toAPValue() const {
   // Just invert the order of the elements.
   std::reverse(Path.begin(), Path.end());
 
-  return APValue(Base, Offset, Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
+  return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
+                 /*IsNullPtr=*/false);
 }
 
 void Pointer::print(llvm::raw_ostream &OS) const {
@@ -348,7 +349,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
 
     // Invalid pointers.
     if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
-        (!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd()))
+        Ptr.isPastEnd())
       return false;
 
     // Primitive values.

diff  --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 5faec75cc3ec5..4f277eb7d9e58 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -556,10 +556,18 @@ class Pointer {
     if (isUnknownSizeArray())
       return false;
 
-    return isElementPastEnd() ||
+    return isElementPastEnd() || isPastEnd() ||
            (getSize() == getOffset() && !isZeroSizeArray());
   }
 
+  /// Checks if the pointer points past the end of the object.
+  bool isPastEnd() const {
+    if (isIntegralPointer())
+      return false;
+
+    return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize();
+  }
+
   /// Checks if the pointer is an out-of-bounds element pointer.
   bool isElementPastEnd() const { return Offset == PastEndMark; }
 

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index f70ca79e216da..630d9b53cca25 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1266,3 +1266,13 @@ static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral cons
                                             // both-note {{in call to}}
 
 #endif
+
+namespace ComparisonAgainstOnePastEnd {
+  int a, b;
+  static_assert(&a + 1 == &b, ""); // both-error {{not an integral constant expression}} \
+                                   // both-note {{comparison against pointer '&a + 1' that points past the end of a complete object has unspecified value}}
+  static_assert(&a == &b + 1, ""); // both-error {{not an integral constant expression}} \
+                                   // both-note {{comparison against pointer '&b + 1' that points past the end of a complete object has unspecified value}}
+
+  static_assert(&a + 1 == &b + 1, ""); // both-error {{static assertion failed}}
+};


        


More information about the cfe-commits mailing list