Skip to content

Commit 6e8a250

Browse files
committed
Only read the requested bits
1 parent ade4a6d commit 6e8a250

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

clang/lib/AST/ByteCode/BitcastBuffer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ struct Bits {
3535
N += O;
3636
return *this;
3737
}
38+
39+
bool operator>=(Bits Other) { return N >= Other.N; }
3840
};
3941

4042
/// A quantity in bytes.

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ static void swapBytes(std::byte *M, size_t N) {
8080
/// We use this to recursively iterate over all fields and elements of a pointer
8181
/// and extract relevant data for a bitcast.
8282
static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
83-
DataFunc F) {
83+
Bits BitsToRead, DataFunc F) {
8484
const Descriptor *FieldDesc = P.getFieldDesc();
8585
assert(FieldDesc);
8686

@@ -97,9 +97,11 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
9797
bool PackedBools = FieldDesc->getType()->isExtVectorBoolType();
9898
unsigned NumElems = FieldDesc->getNumElems();
9999
bool Ok = true;
100-
for (unsigned I = 0; I != NumElems; ++I) {
100+
for (unsigned I = P.getIndex(); I != NumElems; ++I) {
101101
Ok = Ok && F(P.atIndex(I), ElemT, Offset, PackedBools);
102102
Offset += PackedBools ? 1 : ElemSizeInBits;
103+
if (Offset >= BitsToRead)
104+
break;
103105
}
104106
return Ok;
105107
}
@@ -109,8 +111,10 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
109111
QualType ElemType = FieldDesc->getElemQualType();
110112
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
111113
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
112-
enumerateData(P.atIndex(I).narrow(), Ctx, Offset, F);
114+
enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F);
113115
Offset += ElemSizeInBits;
116+
if (Offset >= BitsToRead)
117+
break;
114118
}
115119
return true;
116120
}
@@ -126,14 +130,14 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
126130
Pointer Elem = P.atField(Fi.Offset);
127131
Bits BitOffset =
128132
Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
129-
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
133+
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
130134
}
131135
for (const Record::Base &B : R->bases()) {
132136
Pointer Elem = P.atField(B.Offset);
133137
CharUnits ByteOffset =
134138
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
135139
Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
136-
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
140+
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, BitsToRead, F);
137141
}
138142

139143
return Ok;
@@ -143,8 +147,8 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
143147
}
144148

145149
static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
146-
DataFunc F) {
147-
return enumerateData(P, Ctx, Bits::zero(), F);
150+
Bits BitsToRead, DataFunc F) {
151+
return enumerateData(P, Ctx, Bits::zero(), BitsToRead, F);
148152
}
149153

150154
// This function is constexpr if and only if To, From, and the types of
@@ -222,7 +226,7 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
222226
ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
223227

224228
return enumeratePointerFields(
225-
FromPtr, Ctx,
229+
FromPtr, Ctx, Buffer.size(),
226230
[&](const Pointer &P, PrimType T, Bits BitOffset,
227231
bool PackedBools) -> bool {
228232
// if (!P.isInitialized()) {
@@ -327,7 +331,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
327331
Endian TargetEndianness =
328332
ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
329333
bool Success = enumeratePointerFields(
330-
ToPtr, S.getContext(),
334+
ToPtr, S.getContext(), Buffer.size(),
331335
[&](const Pointer &P, PrimType T, Bits BitOffset,
332336
bool PackedBools) -> bool {
333337
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());

clang/test/AST/ByteCode/builtin-bit-cast.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,21 @@ static_assert(check_round_trip<long long>(splice));
265265
#endif
266266

267267

268+
namespace Overread {
269+
/// This used to crash becaus we were reading all elements of the
270+
/// source array even though we should only be reading 1.
271+
constexpr int a[] = {2,3, 4, 5};
272+
constexpr int b = __builtin_bit_cast(int, *(a + 1));
273+
static_assert(b == 3);
274+
275+
struct S {
276+
int a;
277+
};
278+
constexpr S ss[] = {{1},{2}};
279+
constexpr int c = __builtin_bit_cast(int, *(ss + 1));
280+
static_assert(c == 2);
281+
}
282+
268283

269284
/// ---------------------------------------------------------------------------
270285
/// From here on, it's things copied from test/SemaCXX/constexpr-builtin-bit.cast.cpp

0 commit comments

Comments
 (0)