[clang] [clang][bytecode] Check pointers in GetPtrField{, Pop} (PR #167335)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 10 07:56:15 PST 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/167335
The pointer needs to point to a record.
Fixes https://github.com/llvm/llvm-project/issues/166371
>From d67265a0c14b705b0ed55faef74dcfb480bf3224 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 10 Nov 2025 16:43:21 +0100
Subject: [PATCH] [clang][bytecode] Check pointers in GetPtrField{,Pop}
The pointer needs to point to a record.
Fixes https://github.com/llvm/llvm-project/issues/166371
---
clang/lib/AST/ByteCode/Interp.cpp | 4 ++++
clang/lib/AST/ByteCode/Interp.h | 12 +++++++----
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 10 +++++----
clang/lib/AST/ByteCode/Opcodes.td | 20 ++++++++++++++----
clang/lib/AST/ByteCode/Pointer.h | 27 ++++++++++++++----------
clang/test/AST/ByteCode/invalid.cpp | 4 ++++
6 files changed, 54 insertions(+), 23 deletions(-)
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 cbd60c9f2b37c..3ff6ed6eb68d5 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2318,12 +2318,13 @@ 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();
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 +2333,14 @@ 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>();
+ Pointer Ptr = S.Stk.pop<Pointer>();
+
+ if (Ptr.isBlockPointer())
+ Ptr = Ptr.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;
@@ -3191,7 +3195,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 0ef130c0a55df..664d98b7e0390 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);
@@ -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>(Pointer(B).atIndex(0));
+ S.Stk.push<Pointer>(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<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");
@@ -1910,6 +1910,8 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
}
}
+ // SrcPtr = SrcPtr.expand();
+
assert(Size.getZExtValue() % DestElemSize == 0);
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
return false;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 1785fcf4a7b20..8818579f020ea 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -361,8 +361,14 @@ def NarrowPtr : Opcode;
// [Pointer] -> [Pointer]
def ExpandPtr : Opcode;
// [Pointer, Offset] -> [Pointer]
-def ArrayElemPtr : AluOpcode;
-def ArrayElemPtrPop : AluOpcode;
+def ArrayElemPtr : Opcode {
+ let Types = [IntegralTypeClass];
+ let HasGroup = 1;
+}
+def ArrayElemPtrPop : Opcode {
+ let Types = [IntegralTypeClass];
+ let HasGroup = 1;
+}
def ArrayElemPop : Opcode {
let Args = [ArgUint32];
@@ -536,9 +542,15 @@ def InitElemPop : Opcode {
//===----------------------------------------------------------------------===//
// [Pointer, Integral] -> [Pointer]
-def AddOffset : AluOpcode;
+def AddOffset : Opcode {
+ let Types = [IntegralTypeClass];
+ let HasGroup = 1;
+}
// [Pointer, Integral] -> [Pointer]
-def SubOffset : AluOpcode;
+def SubOffset : Opcode {
+ let Types = [IntegralTypeClass];
+ let HasGroup = 1;
+}
// [Pointer, Pointer] -> [Integral]
def SubPtr : Opcode {
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index cd738ce8b2a3e..0f5de4f6c72b6 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -199,17 +199,20 @@ 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)
- return Pointer(BS.Pointee, Offset, Offset);
+ 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.
+ if (Offset != Base)
+ return Pointer(BS.Pointee, Offset, Offset);
+ }
}
// Otherwise, we're pointing to a non-array element or
@@ -219,6 +222,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/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