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 OffsetHelper(InterpState &S, CodePtr OpPC, template ::T> bool AddOffset(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop(); - Pointer Ptr = S.Stk.pop(); - if (Ptr.isBlockPointer()) - Ptr = Ptr.expand(); + const Pointer &Ptr = S.Stk.pop().expand(); if (std::optional Result = OffsetHelper( S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) { - S.Stk.push(*Result); + S.Stk.push(Result->narrow()); return true; } return false; @@ -2332,11 +2330,11 @@ bool AddOffset(InterpState &S, CodePtr OpPC) { template ::T> bool SubOffset(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop(); - const Pointer &Ptr = S.Stk.pop(); + const Pointer &Ptr = S.Stk.pop().expand(); if (std::optional Result = OffsetHelper( S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) { - S.Stk.push(*Result); + S.Stk.push(Result->narrow()); return true; } return false; @@ -2362,7 +2360,7 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, if (std::optional Result = OffsetHelper(S, OpPC, One, P, /*IsPointerArith=*/true)) { // Store the new value. - Ptr.deref() = *Result; + Ptr.deref() = Result->narrow(); return true; } return false; @@ -2391,8 +2389,8 @@ static inline bool DecPtr(InterpState &S, CodePtr OpPC) { /// 3) Pushes the difference of the indices of the two pointers on the stack. template ::T> inline bool SubPtr(InterpState &S, CodePtr OpPC, bool ElemSizeIsZero) { - const Pointer &LHS = S.Stk.pop(); - const Pointer &RHS = S.Stk.pop(); + const Pointer &LHS = S.Stk.pop().expand(); + const Pointer &RHS = S.Stk.pop().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(Ptr.atIndex(0).narrow()); return true; } - S.Stk.push(Ptr); + S.Stk.push(Ptr.narrow()); return true; } @@ -3114,7 +3112,7 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { S.Stk.push(Ptr.atIndex(0).narrow()); return true; } - S.Stk.push(Ptr); + S.Stk.push(Ptr.narrow()); return true; } @@ -3189,7 +3187,7 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { } if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) { - S.Stk.push(Ptr.atIndex(0)); + S.Stk.push(Ptr.atIndex(0).narrow()); return true; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index cee3c1b8cf8f3..17906cfb88a8b 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(); + const Pointer &StrPtr = S.Stk.pop().expand(); if (ID == Builtin::BIstrlen || ID == Builtin::BIwcslen) diagnoseNonConstexprBuiltin(S, OpPC, ID); @@ -1439,7 +1439,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(B).atIndex(0)); + S.Stk.push(Pointer(B).atIndex(0).narrow()); return true; } @@ -1763,8 +1763,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(); - const Pointer DestPtr = S.Stk.pop(); + Pointer SrcPtr = S.Stk.pop().expand(); + Pointer DestPtr = S.Stk.pop().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 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{}(__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; }