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; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
