[clang] 90e1391 - [clang][bytecode] Check pointers in GetPtrField{,Pop} (#167335)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Nov 16 23:24:49 PST 2025
Author: Timm Baeder
Date: 2025-11-17T08:24:44+01:00
New Revision: 90e1391d18ae68c40d78e023ab8d0be6de67d5f3
URL: https://github.com/llvm/llvm-project/commit/90e1391d18ae68c40d78e023ab8d0be6de67d5f3
DIFF: https://github.com/llvm/llvm-project/commit/90e1391d18ae68c40d78e023ab8d0be6de67d5f3.diff
LOG: [clang][bytecode] Check pointers in GetPtrField{,Pop} (#167335)
The pointer needs to point to a record.
Fixes https://github.com/llvm/llvm-project/issues/166371
Added:
Modified:
clang/lib/AST/ByteCode/Interp.cpp
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/InterpBuiltin.cpp
clang/lib/AST/ByteCode/Pointer.h
clang/test/AST/ByteCode/cxx23.cpp
clang/test/AST/ByteCode/invalid.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 1f2ae92f6068b..280911c324bb1 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1448,6 +1448,10 @@ static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
+ // We can't get the field of something that's not a record.
+ if (!Ptr.getFieldDesc()->isRecord())
+ return false;
+
if ((Ptr.getByteOffset() + Off) >= Ptr.block()->getSize())
return false;
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 19c8d6d850339..3e869c1ee5f2c 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2317,13 +2317,11 @@ std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool AddOffset(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
- Pointer Ptr = S.Stk.pop<Pointer>();
- if (Ptr.isBlockPointer())
- Ptr = Ptr.expand();
+ const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(
S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
- S.Stk.push<Pointer>(*Result);
+ S.Stk.push<Pointer>(Result->narrow());
return true;
}
return false;
@@ -2332,11 +2330,11 @@ bool AddOffset(InterpState &S, CodePtr OpPC) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool SubOffset(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
- const Pointer &Ptr = S.Stk.pop<Pointer>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(
S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
- S.Stk.push<Pointer>(*Result);
+ S.Stk.push<Pointer>(Result->narrow());
return true;
}
return false;
@@ -2362,7 +2360,7 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
if (std::optional<Pointer> Result =
OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {
// Store the new value.
- Ptr.deref<Pointer>() = *Result;
+ Ptr.deref<Pointer>() = Result->narrow();
return true;
}
return false;
@@ -2391,8 +2389,8 @@ static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
/// 3) Pushes the
diff erence of the indices of the two pointers on the stack.
template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool SubPtr(InterpState &S, CodePtr OpPC, bool ElemSizeIsZero) {
- const Pointer &LHS = S.Stk.pop<Pointer>();
- const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>().expand();
+ const Pointer &RHS = S.Stk.pop<Pointer>().expand();
if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
S.FFDiag(S.Current->getSource(OpPC),
@@ -3083,7 +3081,7 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
return true;
}
- S.Stk.push<Pointer>(Ptr);
+ S.Stk.push<Pointer>(Ptr.narrow());
return true;
}
@@ -3114,7 +3112,7 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
return true;
}
- S.Stk.push<Pointer>(Ptr);
+ S.Stk.push<Pointer>(Ptr.narrow());
return true;
}
@@ -3189,7 +3187,7 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
}
if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
- S.Stk.push<Pointer>(Ptr.atIndex(0));
+ S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 93ce1d50b13b0..afcbe9d4f5b81 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -296,7 +296,7 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call, unsigned ID) {
- const Pointer &StrPtr = S.Stk.pop<Pointer>();
+ const Pointer &StrPtr = S.Stk.pop<Pointer>().expand();
if (ID == Builtin::BIstrlen || ID == Builtin::BIwcslen)
diagnoseNonConstexprBuiltin(S, OpPC, ID);
@@ -1440,7 +1440,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
Allocator.allocate(Desc, NumElems.getZExtValue(), S.Ctx.getEvalID(),
DynamicAllocator::Form::Operator);
assert(B);
- S.Stk.push<Pointer>(Pointer(B).atIndex(0));
+ S.Stk.push<Pointer>(Pointer(B).atIndex(0).narrow());
return true;
}
@@ -1764,8 +1764,8 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
assert(Call->getNumArgs() == 3);
const ASTContext &ASTCtx = S.getASTContext();
APSInt Size = popToAPSInt(S, Call->getArg(2));
- const Pointer SrcPtr = S.Stk.pop<Pointer>();
- const Pointer DestPtr = S.Stk.pop<Pointer>();
+ Pointer SrcPtr = S.Stk.pop<Pointer>().expand();
+ Pointer DestPtr = S.Stk.pop<Pointer>().expand();
assert(!Size.isSigned() && "memcpy and friends take an unsigned size");
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 6efec48df71cb..57c8e45609027 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -199,17 +199,19 @@ class Pointer {
return Pointer(BS.Pointee, sizeof(InlineDescriptor),
Offset == 0 ? Offset : PastEndMark);
- // Pointer is one past end - magic offset marks that.
- if (isOnePastEnd())
- return Pointer(BS.Pointee, Base, PastEndMark);
-
- if (Offset != Base) {
- // If we're pointing to a primitive array element, there's nothing to do.
- if (inPrimitiveArray())
- return *this;
- // Pointer is to a composite array element - enter it.
- if (Offset != Base)
+ if (inArray()) {
+ // Pointer is one past end - magic offset marks that.
+ if (isOnePastEnd())
+ return Pointer(BS.Pointee, Base, PastEndMark);
+
+ if (Offset != Base) {
+ // If we're pointing to a primitive array element, there's nothing to
+ // do.
+ if (inPrimitiveArray())
+ return *this;
+ // Pointer is to a composite array element - enter it.
return Pointer(BS.Pointee, Offset, Offset);
+ }
}
// Otherwise, we're pointing to a non-array element or
@@ -219,6 +221,8 @@ class Pointer {
/// Expands a pointer to the containing array, undoing narrowing.
[[nodiscard]] Pointer expand() const {
+ if (!isBlockPointer())
+ return *this;
assert(isBlockPointer());
Block *Pointee = BS.Pointee;
diff --git a/clang/test/AST/ByteCode/cxx23.cpp b/clang/test/AST/ByteCode/cxx23.cpp
index ce0a4777ffa9b..c5d26925ce11b 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -449,3 +449,27 @@ namespace VolatileWrites {
static_assert(test7(12)); // all-error {{not an integral constant expression}} \
// all-note {{in call to}}
}
+
+namespace AIEWithIndex0Narrows {
+ template <class _Tp> struct greater {
+ constexpr void operator()(_Tp, _Tp) {}
+ };
+ struct S {
+ constexpr S() : i_() {}
+ int i_;
+ };
+
+ constexpr void sort(S *__first) {
+ for (int __start = 0; __start >= 0; --__start) {
+ greater<S>{}(__first[0], __first[0]);
+ }
+ }
+ constexpr bool test() {
+ S *ia = new S[2];
+
+ sort(ia + 1);
+ delete[] ia;
+ return true;
+ }
+ static_assert(test());
+}
diff --git a/clang/test/AST/ByteCode/invalid.cpp b/clang/test/AST/ByteCode/invalid.cpp
index 115c8663079a1..6b49cc44d64df 100644
--- a/clang/test/AST/ByteCode/invalid.cpp
+++ b/clang/test/AST/ByteCode/invalid.cpp
@@ -106,4 +106,8 @@ namespace InvalidBitCast {
return ((sockaddr_in *)&addr)->sin_addr.s_addr;
}
+
+ struct s { int a; int b[1]; };
+ struct s myx;
+ int *myy = ((struct s *)&myx.a)->b;
}
More information about the cfe-commits
mailing list