Skip to content

Commit ff8a6ca

Browse files
committed
overlapping subobjects + opague pointer
1 parent b7b9714 commit ff8a6ca

File tree

3 files changed

+231
-80
lines changed

3 files changed

+231
-80
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 102 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@
6363
#include <optional>
6464
#include <sstream>
6565

66+
67+
68+
#include <iostream>
69+
6670
using namespace clang;
6771
using namespace CodeGen;
6872
using namespace llvm;
@@ -2456,90 +2460,127 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
24562460
return RValue::get(CGF->Builder.CreateCall(UBF, Args));
24572461
}
24582462

2459-
static void RecursivelyZeroNonValueBits(CodeGenFunction &CGF, Value *Ptr,
2460-
QualType Ty) {
2461-
auto *I8Ptr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy);
2462-
auto *Zero = ConstantInt::get(CGF.Int8Ty, 0);
2463-
auto WriteZeroAtOffset = [&](size_t Offset) {
2464-
auto Index = ConstantInt::get(CGF.IntTy, Offset);
2465-
auto Element = CGF.Builder.CreateGEP(I8Ptr, Index);
2466-
CGF.Builder.CreateAlignedStore(
2467-
Zero, Element,
2468-
CharUnits::One().alignmentAtOffset(CharUnits::fromQuantity(Offset)));
2469-
};
2470-
auto GetStructLayout = [&CGF](llvm::Type *Ty) {
2471-
auto ST = cast<StructType>(Ty);
2472-
return CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
2473-
};
2463+
template <class T>
2464+
void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty, size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset);
24742465

2475-
auto ST = cast<StructType>(Ptr->getType()->getPointerElementType());
2476-
auto SL = GetStructLayout(ST);
2466+
template <class T>
2467+
void ClearPaddingStruct(CodeGenFunction &CGF, Value *Ptr, QualType Ty, StructType *ST,
2468+
size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset) {
2469+
std::cerr << "\n struct! " << ST->getName().data() << std::endl;
2470+
auto SL = CGF.CGM.getModule().getDataLayout().getStructLayout(ST);
24772471
auto R = cast<CXXRecordDecl>(Ty->getAsRecordDecl());
24782472
const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R);
2479-
size_t RunningOffset = 0;
24802473
for (auto Base : R->bases()) {
2474+
std::cerr << "\n\n base!" << std::endl;
24812475
// Zero padding between base elements.
24822476
auto BaseRecord = cast<CXXRecordDecl>(Base.getType()->getAsRecordDecl());
24832477
auto Offset = static_cast<size_t>(
24842478
ASTLayout.getBaseClassOffset(BaseRecord).getQuantity());
2485-
for (; RunningOffset < Offset; ++RunningOffset) {
2486-
WriteZeroAtOffset(RunningOffset);
2487-
}
24882479
// Recursively zero out base classes.
24892480
auto Index = SL->getElementContainingOffset(Offset);
2490-
auto BaseElement = CGF.Builder.CreateStructGEP(Ptr, Index);
2491-
RecursivelyZeroNonValueBits(CGF, BaseElement, Base.getType());
2492-
// Use the LLVM StructType data layout so we pick up on packed types.
2493-
auto SL = GetStructLayout(ST->getElementType(Index));
2494-
auto Size = SL->getSizeInBytes();
2495-
RunningOffset = Offset + Size;
2481+
Value *Idx = CGF.Builder.getSize(Index);
2482+
llvm::Type *CurrentBaseType = CGF.ConvertTypeForMem(Base.getType());
2483+
Value *BaseElement = CGF.Builder.CreateGEP(CurrentBaseType, Ptr, Idx);
2484+
RecursivelyClearPaddingImpl(CGF, BaseElement, Base.getType(), CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
24962485
}
24972486

24982487
size_t NumFields = std::distance(R->field_begin(), R->field_end());
24992488
auto CurrentField = R->field_begin();
25002489
for (size_t I = 0; I < NumFields; ++I, ++CurrentField) {
25012490
// Size needs to be in bytes so we can compare it later.
25022491
auto Offset = ASTLayout.getFieldOffset(I) / 8;
2503-
for (; RunningOffset < Offset; ++RunningOffset) {
2504-
WriteZeroAtOffset(RunningOffset);
2505-
}
2506-
25072492
auto Index = SL->getElementContainingOffset(Offset);
2508-
// If this field is an object, it may have non-zero padding.
2509-
if (CurrentField->getType()->isRecordType()) {
2510-
auto Element = CGF.Builder.CreateStructGEP(Ptr, Index);
2511-
RecursivelyZeroNonValueBits(CGF, Element, CurrentField->getType());
2512-
}
2493+
Value *Idx = CGF.Builder.getSize(Index);
2494+
llvm::Type *CurrentFieldType = CGF.ConvertTypeForMem(CurrentField->getType());
2495+
Value *Element = CGF.Builder.CreateGEP(CurrentFieldType, Ptr, Idx);
2496+
RecursivelyClearPaddingImpl(CGF, Element, CurrentField->getType(), CurrentStartOffset + Offset, RunningOffset, WriteZeroAtOffset);
2497+
}
2498+
}
25132499

2514-
// TODO: warn if non-constant array type.
2515-
if (isa<ConstantArrayType>(CurrentField->getType()) &&
2516-
CurrentField->getType()
2517-
->getArrayElementTypeNoTypeQual()
2518-
->isRecordType()) {
2519-
auto FieldElement = CGF.Builder.CreateStructGEP(Ptr, Index);
2520-
auto AT = cast<ConstantArrayType>(CurrentField->getType());
2521-
for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
2522-
++ArrIndex) {
2523-
auto ElementRecord = AT->getElementType()->getAsRecordDecl();
2524-
auto ElementAlign =
2525-
CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment();
2526-
Address FieldElementAddr{FieldElement, ElementAlign};
2527-
auto Element =
2528-
CGF.Builder.CreateConstArrayGEP(FieldElementAddr, ArrIndex);
2529-
RecursivelyZeroNonValueBits(CGF, Element.getPointer(),
2530-
AT->getElementType());
2531-
}
2500+
template <class T>
2501+
void ClearPaddingConstantArray(CodeGenFunction &CGF, Value *Ptr, llvm::Type *Type, ConstantArrayType const *AT,
2502+
size_t CurrentStartOffset, size_t &RunningOffset, T&& WriteZeroAtOffset) {
2503+
for (size_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue();
2504+
++ArrIndex) {
2505+
2506+
QualType ElementQualType = AT->getElementType();
2507+
2508+
auto *ElementRecord = ElementQualType->getAsRecordDecl();
2509+
if(!ElementRecord){
2510+
std::cerr<< "\n\n null!" << std::endl;
25322511
}
2512+
auto ElementAlign =ElementRecord?
2513+
CGF.getContext().getASTRecordLayout(ElementRecord).getAlignment():
2514+
CGF.getContext().getTypeAlignInChars(ElementQualType);
2515+
2516+
std::cerr<< "\n\n align: " << ElementAlign.getQuantity() << std::endl;
2517+
2518+
// Value *Idx = CGF.Builder.getSize(0);
2519+
// Value *ArrayElement = CGF.Builder.CreateGEP(ElementType, Ptr, Idx);
25332520

2534-
auto Size = CGF.CGM.getModule()
2521+
Address FieldElementAddr{Ptr, Type, ElementAlign};
2522+
2523+
auto Element =
2524+
CGF.Builder.CreateConstArrayGEP(FieldElementAddr, ArrIndex);
2525+
auto *ElementType = CGF.ConvertTypeForMem(ElementQualType);
2526+
auto AllocSize = CGF.CGM.getModule().getDataLayout().getTypeAllocSize(ElementType);
2527+
std::cerr << "\n\n clearing array index! " << ArrIndex << std::endl;
2528+
RecursivelyClearPaddingImpl(CGF, Element.getPointer(), ElementQualType, CurrentStartOffset + ArrIndex * AllocSize.getKnownMinValue(), RunningOffset, WriteZeroAtOffset);
2529+
}
2530+
}
2531+
2532+
template <class T>
2533+
void RecursivelyClearPaddingImpl(CodeGenFunction &CGF, Value *Ptr, QualType Ty, size_t CurrentStartOffset,
2534+
size_t& RunningOffset, T&& WriteZeroAtOffset) {
2535+
2536+
std::cerr << "\n\n zero padding before current ["<< RunningOffset << ", " << CurrentStartOffset<< ")"<< std::endl;
2537+
for (; RunningOffset < CurrentStartOffset; ++RunningOffset) {
2538+
WriteZeroAtOffset(RunningOffset);
2539+
}
2540+
auto Type = CGF.ConvertTypeForMem(Ty);
2541+
auto Size = CGF.CGM.getModule()
25352542
.getDataLayout()
2536-
.getTypeSizeInBits(ST->getElementType(Index))
2537-
.getKnownMinSize() /
2538-
8;
2539-
RunningOffset = Offset + Size;
2543+
.getTypeSizeInBits(Type)
2544+
.getKnownMinValue() / 8;
2545+
2546+
if (auto *AT = dyn_cast<ConstantArrayType>(Ty)) {
2547+
ClearPaddingConstantArray(CGF, Ptr, Type, AT, CurrentStartOffset, RunningOffset, WriteZeroAtOffset);
2548+
}
2549+
else if (auto *ST = dyn_cast<StructType>(Type)) {
2550+
ClearPaddingStruct(CGF, Ptr, Ty, ST, CurrentStartOffset, RunningOffset, WriteZeroAtOffset);
2551+
} else {
2552+
std::cerr << "\n\n increment running offset from: " << RunningOffset << " to " << RunningOffset + Size << std::endl;
2553+
RunningOffset += Size;
25402554
}
2541-
// Clear all bits after the last field.
2542-
auto Size = SL->getSizeInBytes();
2555+
2556+
}
2557+
2558+
static void RecursivelyZeroNonValueBits(CodeGenFunction &CGF, Value *Ptr,
2559+
QualType Ty) {
2560+
auto *I8Ptr = CGF.Builder.CreateBitCast(Ptr, CGF.Int8PtrTy);
2561+
auto *Zero = ConstantInt::get(CGF.Int8Ty, 0);
2562+
auto WriteZeroAtOffset = [&](size_t Offset) {
2563+
auto *Index = ConstantInt::get(CGF.IntTy, Offset);
2564+
auto *Element = CGF.Builder.CreateGEP(CGF.Int8Ty, I8Ptr, Index);
2565+
CGF.Builder.CreateAlignedStore(
2566+
Zero, Element,
2567+
CharUnits::One().alignmentAtOffset(CharUnits::fromQuantity(Offset)));
2568+
};
2569+
2570+
2571+
size_t RunningOffset = 0;
2572+
2573+
RecursivelyClearPaddingImpl(CGF, Ptr, Ty, 0, RunningOffset, WriteZeroAtOffset);
2574+
2575+
// Clear tail padding
2576+
auto Type = CGF.ConvertTypeForMem(Ty);
2577+
2578+
auto Size = CGF.CGM.getModule()
2579+
.getDataLayout()
2580+
.getTypeSizeInBits(Type)
2581+
.getKnownMinValue() / 8;
2582+
2583+
std::cerr << "\n\n zero tail padding ["<< RunningOffset << ", " << Size << ")"<< std::endl;
25432584
for (; RunningOffset < Size; ++RunningOffset) {
25442585
WriteZeroAtOffset(RunningOffset);
25452586
}

clang/lib/Sema/SemaChecking.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2328,23 +2328,23 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
23282328
case Builtin::BI__builtin_launder:
23292329
return SemaBuiltinLaunder(*this, TheCall);
23302330
case Builtin::BI__builtin_zero_non_value_bits: {
2331-
const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts();
2332-
const QualType PtrArgType = PtrArg->getType();
2333-
if (!PtrArgType->isPointerType() ||
2334-
!PtrArgType->getPointeeType()->isRecordType()) {
2335-
Diag(PtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
2336-
<< PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType
2337-
<< "structure pointer";
2338-
return ExprError();
2339-
}
2340-
if (PtrArgType->getPointeeType().isConstQualified()) {
2341-
Diag(PtrArg->getBeginLoc(), diag::err_typecheck_assign_const)
2342-
<< TheCall->getSourceRange() << 5 /*ConstUnknown*/;
2343-
return ExprError();
2344-
}
2345-
if (RequireCompleteType(PtrArg->getBeginLoc(), PtrArgType->getPointeeType(),
2346-
diag::err_typecheck_decl_incomplete_type))
2347-
return ExprError();
2331+
// const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts();
2332+
// const QualType PtrArgType = PtrArg->getType();
2333+
// if (!PtrArgType->isPointerType() ||
2334+
// !PtrArgType->getPointeeType()->isRecordType()) {
2335+
// Diag(PtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
2336+
// << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType
2337+
// << "structure pointer";
2338+
// return ExprError();
2339+
// }
2340+
// if (PtrArgType->getPointeeType().isConstQualified()) {
2341+
// Diag(PtrArg->getBeginLoc(), diag::err_typecheck_assign_const)
2342+
// << TheCall->getSourceRange() << 5 /*ConstUnknown*/;
2343+
// return ExprError();
2344+
// }
2345+
// if (RequireCompleteType(PtrArg->getBeginLoc(), PtrArgType->getPointeeType(),
2346+
// diag::err_typecheck_decl_incomplete_type))
2347+
// return ExprError();
23482348
break;
23492349
}
23502350
case Builtin::BI__sync_fetch_and_add:

clang/test/CodeGenCXX/builtin-zero-non-value-bits.cpp

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@
77
#include <cstring>
88
#include <new>
99

10+
template <class T>
11+
void print_bytes(const T *object)
12+
{
13+
auto size = sizeof(T);
14+
const unsigned char * const bytes = reinterpret_cast<const unsigned char *>(object);
15+
size_t i;
16+
17+
fprintf(stderr, "[ ");
18+
for(i = 0; i < size; i++)
19+
{
20+
fprintf(stderr, "%02x ", bytes[i]);
21+
}
22+
fprintf(stderr, "]\n");
23+
}
24+
1025
template <size_t A1, size_t A2, class T>
1126
struct alignas(A1) BasicWithPadding {
1227
T x;
@@ -74,7 +89,6 @@ void testAllForType(T a, T b, T c, T d) {
7489
assert(memcmp(&basic1, &basic2, sizeof(B)) != 0);
7590
__builtin_zero_non_value_bits(&basic2);
7691
assert(memcmp(&basic1, &basic2, sizeof(B)) == 0);
77-
7892
using A = SpacedArrayMembers<A1, A2, 2, T>;
7993
A arr1;
8094
memset(&arr1, 0, sizeof(A));
@@ -219,7 +233,104 @@ struct Foo {
219233
typedef float Float4Vec __attribute__((ext_vector_type(4)));
220234
typedef float Float3Vec __attribute__((ext_vector_type(3)));
221235

236+
struct S1 {
237+
int x = 0;
238+
char c = 0;
239+
};
240+
241+
struct S2{
242+
[[no_unique_address]] S1 s1;
243+
bool b;
244+
long double l;
245+
bool b2;
246+
};
247+
248+
struct S3{
249+
[[no_unique_address]] S1 s1;
250+
bool b;
251+
};
252+
253+
struct alignas(32) S4 {
254+
int i;
255+
};
256+
struct B1{
257+
258+
};
259+
260+
struct B2 {
261+
int x;
262+
};
263+
struct B3{
264+
char c;
265+
};
266+
267+
struct B4{
268+
bool b;
269+
};
270+
271+
struct B5{
272+
int x2;
273+
};
274+
275+
struct D:B1,B2,B3,B4,B5{
276+
long double l;
277+
bool b2;
278+
};
279+
280+
222281
int main() {
282+
/*
283+
S2 s2{};
284+
285+
memset(&s2, 42, sizeof(S2));
286+
s2.s1.x = 0x12345678;
287+
s2.s1.c = 0xff;
288+
s2.b = true;
289+
s2.l = 3.333;
290+
s2.b2 = true;
291+
print_bytes(&s2);
292+
__builtin_zero_non_value_bits(&s2);
293+
print_bytes(&s2);
294+
295+
D s2{};
296+
memset(&s2, 42, sizeof(D));
297+
s2.x = 0x12345678;
298+
s2.c = 0xff;
299+
s2.b = true;
300+
s2.x2 = 0x87654321;
301+
s2.l = 3.333;
302+
s2.b2 = true;
303+
print_bytes(&s2);
304+
__builtin_zero_non_value_bits(&s2);
305+
print_bytes(&s2);
306+
307+
S3 s2[2];
308+
309+
memset(&s2, 42, 2*sizeof(S3));
310+
s2[0].s1.x = 0x12345678;
311+
s2[0].s1.c = 0xff;
312+
s2[0].b = true;
313+
s2[1].s1.x = 0x12345678;
314+
s2[1].s1.c = 0xff;
315+
s2[1].b = true;
316+
print_bytes(&s2);
317+
__builtin_zero_non_value_bits(&s2);
318+
print_bytes(&s2);
319+
320+
*/
321+
/*
322+
S4 s2[2];
323+
324+
memset(&s2, 42, 2*sizeof(S4));
325+
s2[0].i = 0x12345678;
326+
s2[1].i = 0x12345678;
327+
print_bytes(&s2);
328+
__builtin_zero_non_value_bits(&s2);
329+
print_bytes(&s2);
330+
331+
332+
assert(false);
333+
*/
223334
testAllForType<32, 16, char>(11, 22, 33, 44);
224335
testAllForType<64, 32, char>(4, 5, 6, 7);
225336
testAllForType<32, 16, volatile char>(11, 22, 33, 44);
@@ -244,6 +355,5 @@ int main() {
244355
testAllForType<128, 128, Float4Vec>(4, 5, 6, 7);
245356

246357
otherTests();
247-
248358
return 0;
249359
}

0 commit comments

Comments
 (0)