[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