[clang] a13f036 - [clang][Interp] Check one-past-the-end pointers in GetPtrField
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 5 02:01:33 PDT 2023
Author: Timm Bäder
Date: 2023-09-05T11:00:40+02:00
New Revision: a13f036949b05e5f9d1ac1e33fed465c939aca62
URL: https://github.com/llvm/llvm-project/commit/a13f036949b05e5f9d1ac1e33fed465c939aca62
DIFF: https://github.com/llvm/llvm-project/commit/a13f036949b05e5f9d1ac1e33fed465c939aca62.diff
LOG: [clang][Interp] Check one-past-the-end pointers in GetPtrField
Rename CheckBaseDerived to something more general and call it in
GetPtrField() as well, so we don't crash later in Pointer::toAPValue().
Differential Revision: https://reviews.llvm.org/D149149
Added:
Modified:
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Interp.h
clang/test/AST/Interp/records.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 23c54b3898e102..719a96daaebdd7 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -213,8 +213,8 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-bool CheckBaseDerived(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- CheckSubobjectKind CSK) {
+bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK) {
if (!Ptr.isOnePastEnd())
return true;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 006abc0f0e94ac..b87a5c1cbd0e48 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -67,9 +67,9 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
CheckSubobjectKind CSK);
-/// Checks if accessing a base or derived record of the given pointer is valid.
-bool CheckBaseDerived(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- CheckSubobjectKind CSK);
+/// Checks if Ptr is a one-past-the-end pointer.
+bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK);
/// Checks if a pointer points to const storage.
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
@@ -1121,6 +1121,9 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false;
+ if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
+ return false;
+
S.Stk.push<Pointer>(Ptr.atField(Off));
return true;
}
@@ -1165,7 +1168,7 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
return false;
- if (!CheckBaseDerived(S, OpPC, Ptr, CSK_Derived))
+ if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
return false;
S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
return true;
@@ -1175,7 +1178,7 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
return false;
- if (!CheckBaseDerived(S, OpPC, Ptr, CSK_Base))
+ if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
return false;
S.Stk.push<Pointer>(Ptr.atField(Off));
return true;
@@ -1185,7 +1188,7 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
return false;
- if (!CheckBaseDerived(S, OpPC, Ptr, CSK_Base))
+ if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
return false;
S.Stk.push<Pointer>(Ptr.atField(Off));
return true;
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index b559f1f8b95b0a..2b79ec8be0311d 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -531,6 +531,29 @@ namespace DeclRefs {
//static_assert(b.a.f == 100, "");
}
+namespace PointerArith {
+ struct A {};
+ struct B : A { int n; };
+
+ B b = {};
+ constexpr A *a1 = &b;
+ constexpr B *b1 = &b + 1;
+ constexpr B *b2 = &b + 0;
+
+#if 0
+ constexpr A *a2 = &b + 1; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{cannot access base class of pointer past the end of object}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{cannot access base class of pointer past the end of object}}
+
+#endif
+ constexpr const int *pn = &(&b + 1)->n; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{cannot access field of pointer past the end of object}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{cannot access field of pointer past the end of object}}
+
+}
+
#if __cplusplus >= 202002L
namespace VirtualCalls {
namespace Obvious {
More information about the cfe-commits
mailing list