Skip to content

Commit 0b30881

Browse files
tbaederrgithub-actions[bot]
authored andcommitted
Automerge: [clang][bytecode] Adjust pointers when moving them (#168053)
When calling Block::movePointersTo(), the two blocks might have different metadata sizes, which causes the final pointer to be incorrect and point to garbage. Adjust the pointer base and offset accordingly. Fixes llvm/llvm-project#168018
2 parents acb4a1e + dc3ae60 commit 0b30881

File tree

4 files changed

+41
-1
lines changed

4 files changed

+41
-1
lines changed

clang/lib/AST/ByteCode/InterpBlock.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,21 @@ bool Block::hasPointer(const Pointer *P) const {
102102

103103
void Block::movePointersTo(Block *B) {
104104
assert(B != this);
105+
unsigned MDDiff = static_cast<int>(B->Desc->getMetadataSize()) -
106+
static_cast<int>(Desc->getMetadataSize());
105107

106108
while (Pointers) {
107109
Pointer *P = Pointers;
108110

109111
this->removePointer(P);
110112
P->BS.Pointee = B;
113+
114+
// If the metadata size changed between the two blocks, move the pointer
115+
// base/offset. Realistically, this should only happen when we move pointers
116+
// from a dummy pointer to a global one.
117+
P->BS.Base += MDDiff;
118+
P->Offset += MDDiff;
119+
111120
B->addPointer(P);
112121
}
113122
assert(!this->hasPointers());

clang/lib/AST/ByteCode/MemberPointer.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
2323
if (!Base.isBlockPointer())
2424
return std::nullopt;
2525

26+
unsigned BlockMDSize = Base.block()->getDescriptor()->getMetadataSize();
27+
28+
if (PtrOffset >= 0) {
29+
// If the resulting base would be too small, return nullopt.
30+
if (Base.BS.Base < static_cast<unsigned>(PtrOffset) ||
31+
(Base.BS.Base - PtrOffset < BlockMDSize))
32+
return std::nullopt;
33+
}
34+
2635
Pointer CastedBase =
2736
(PtrOffset < 0 ? Base.atField(-PtrOffset) : Base.atFieldSub(PtrOffset));
2837

@@ -31,7 +40,7 @@ std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
3140
return std::nullopt;
3241

3342
unsigned Offset = 0;
34-
Offset += CastedBase.block()->getDescriptor()->getMetadataSize();
43+
Offset += BlockMDSize;
3544

3645
if (const auto *FD = dyn_cast<FieldDecl>(Dcl)) {
3746
if (FD->getParent() == BaseRecord->getDecl())

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
3333
Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
3434
: Offset(Offset), StorageKind(Storage::Block) {
3535
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
36+
assert(Base >= Pointee->getDescriptor()->getMetadataSize());
3637

3738
BS = {Pointee, Base, nullptr, nullptr};
3839

clang/test/AST/ByteCode/cxx11.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,24 @@ namespace PointerCast {
398398
// expected-note {{cast that performs the conversions of a reinterpret_cast}}
399399
};
400400
}
401+
402+
namespace DummyToGlobalBlockMove {
403+
struct Baz {
404+
unsigned int n;
405+
};
406+
407+
struct AP {
408+
const AP *p;
409+
const Baz *lp;
410+
};
411+
412+
class Bar {
413+
public:
414+
static Baz _m[];
415+
static const AP m;
416+
};
417+
418+
const AP Bar::m = {0, &Bar::_m[0]};
419+
Baz Bar::_m[] = {{0}};
420+
const AP m = {&Bar ::m};
421+
}

0 commit comments

Comments
 (0)