Skip to content

Commit 11a74d1

Browse files
committed
Refactor EmitTypeCheck into three more precise SanitizerDebugLocations
1 parent aead894 commit 11a74d1

File tree

1 file changed

+102
-89
lines changed

1 file changed

+102
-89
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 102 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -744,111 +744,116 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
744744
if (Ty.isVolatileQualified())
745745
return;
746746

747-
auto CheckHandler = SanitizerHandler::TypeMismatch;
748-
// SO_Vptr's corresponding handler is DynamicTypeCacheMiss, not TypeMismatch.
749-
// However, it relies upon IsGuaranteedNonNull, hence the instructions cannot
750-
// be fully separated from the TypeMismatch.
751-
SanitizerDebugLocation SanScope(
752-
this,
753-
{SanitizerKind::SO_Null, SanitizerKind::SO_ObjectSize,
754-
SanitizerKind::SO_Alignment, SanitizerKind::SO_Vptr},
755-
CheckHandler);
756-
757-
SmallVector<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>, 3>
758-
Checks;
759-
llvm::BasicBlock *Done = nullptr;
760-
761747
// Quickly determine whether we have a pointer to an alloca. It's possible
762748
// to skip null checks, and some alignment checks, for these pointers. This
763749
// can reduce compile-time significantly.
764750
auto PtrToAlloca = dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCasts());
765751

766-
llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
767752
llvm::Value *IsNonNull = nullptr;
768753
bool IsGuaranteedNonNull =
769754
SkippedChecks.has(SanitizerKind::Null) || PtrToAlloca;
770-
bool AllowNullPointers = isNullPointerAllowed(TCK);
771-
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
772-
!IsGuaranteedNonNull) {
773-
// The glvalue must not be an empty glvalue.
774-
IsNonNull = Builder.CreateIsNotNull(Ptr);
775755

776-
// The IR builder can constant-fold the null check if the pointer points to
777-
// a constant.
778-
IsGuaranteedNonNull = IsNonNull == True;
779-
780-
// Skip the null check if the pointer is known to be non-null.
781-
if (!IsGuaranteedNonNull) {
782-
if (AllowNullPointers) {
783-
// When performing pointer casts, it's OK if the value is null.
784-
// Skip the remaining checks in that case.
785-
Done = createBasicBlock("null");
786-
llvm::BasicBlock *Rest = createBasicBlock("not.null");
787-
Builder.CreateCondBr(IsNonNull, Rest, Done);
788-
EmitBlock(Rest);
789-
} else {
790-
Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::SO_Null));
756+
llvm::BasicBlock *Done = nullptr;
757+
bool DoneViaNullSanitize = false;
758+
759+
{
760+
auto CheckHandler = SanitizerHandler::TypeMismatch;
761+
SanitizerDebugLocation SanScope(this,
762+
{SanitizerKind::SO_Null,
763+
SanitizerKind::SO_ObjectSize,
764+
SanitizerKind::SO_Alignment},
765+
CheckHandler);
766+
767+
SmallVector<std::pair<llvm::Value *, SanitizerKind::SanitizerOrdinal>, 3>
768+
Checks;
769+
770+
llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
771+
bool AllowNullPointers = isNullPointerAllowed(TCK);
772+
if ((SanOpts.has(SanitizerKind::Null) || AllowNullPointers) &&
773+
!IsGuaranteedNonNull) {
774+
// The glvalue must not be an empty glvalue.
775+
IsNonNull = Builder.CreateIsNotNull(Ptr);
776+
777+
// The IR builder can constant-fold the null check if the pointer points
778+
// to a constant.
779+
IsGuaranteedNonNull = IsNonNull == True;
780+
781+
// Skip the null check if the pointer is known to be non-null.
782+
if (!IsGuaranteedNonNull) {
783+
if (AllowNullPointers) {
784+
// When performing pointer casts, it's OK if the value is null.
785+
// Skip the remaining checks in that case.
786+
Done = createBasicBlock("null");
787+
DoneViaNullSanitize = true;
788+
llvm::BasicBlock *Rest = createBasicBlock("not.null");
789+
Builder.CreateCondBr(IsNonNull, Rest, Done);
790+
EmitBlock(Rest);
791+
} else {
792+
Checks.push_back(std::make_pair(IsNonNull, SanitizerKind::SO_Null));
793+
}
791794
}
792795
}
793-
}
794796

795-
if (SanOpts.has(SanitizerKind::ObjectSize) &&
796-
!SkippedChecks.has(SanitizerKind::ObjectSize) &&
797-
!Ty->isIncompleteType()) {
798-
uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity();
799-
llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize);
800-
if (ArraySize)
801-
Size = Builder.CreateMul(Size, ArraySize);
802-
803-
// Degenerate case: new X[0] does not need an objectsize check.
804-
llvm::Constant *ConstantSize = dyn_cast<llvm::Constant>(Size);
805-
if (!ConstantSize || !ConstantSize->isNullValue()) {
806-
// The glvalue must refer to a large enough storage region.
807-
// FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation
808-
// to check this.
809-
// FIXME: Get object address space
810-
llvm::Type *Tys[2] = { IntPtrTy, Int8PtrTy };
811-
llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
812-
llvm::Value *Min = Builder.getFalse();
813-
llvm::Value *NullIsUnknown = Builder.getFalse();
814-
llvm::Value *Dynamic = Builder.getFalse();
815-
llvm::Value *LargeEnough = Builder.CreateICmpUGE(
816-
Builder.CreateCall(F, {Ptr, Min, NullIsUnknown, Dynamic}), Size);
817-
Checks.push_back(
818-
std::make_pair(LargeEnough, SanitizerKind::SO_ObjectSize));
797+
if (SanOpts.has(SanitizerKind::ObjectSize) &&
798+
!SkippedChecks.has(SanitizerKind::ObjectSize) &&
799+
!Ty->isIncompleteType()) {
800+
uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity();
801+
llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize);
802+
if (ArraySize)
803+
Size = Builder.CreateMul(Size, ArraySize);
804+
805+
// Degenerate case: new X[0] does not need an objectsize check.
806+
llvm::Constant *ConstantSize = dyn_cast<llvm::Constant>(Size);
807+
if (!ConstantSize || !ConstantSize->isNullValue()) {
808+
// The glvalue must refer to a large enough storage region.
809+
// FIXME: If Address Sanitizer is enabled, insert dynamic
810+
// instrumentation
811+
// to check this.
812+
// FIXME: Get object address space
813+
llvm::Type *Tys[2] = {IntPtrTy, Int8PtrTy};
814+
llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, Tys);
815+
llvm::Value *Min = Builder.getFalse();
816+
llvm::Value *NullIsUnknown = Builder.getFalse();
817+
llvm::Value *Dynamic = Builder.getFalse();
818+
llvm::Value *LargeEnough = Builder.CreateICmpUGE(
819+
Builder.CreateCall(F, {Ptr, Min, NullIsUnknown, Dynamic}), Size);
820+
Checks.push_back(
821+
std::make_pair(LargeEnough, SanitizerKind::SO_ObjectSize));
822+
}
819823
}
820-
}
821824

822-
llvm::MaybeAlign AlignVal;
823-
llvm::Value *PtrAsInt = nullptr;
824-
825-
if (SanOpts.has(SanitizerKind::Alignment) &&
826-
!SkippedChecks.has(SanitizerKind::Alignment)) {
827-
AlignVal = Alignment.getAsMaybeAlign();
828-
if (!Ty->isIncompleteType() && !AlignVal)
829-
AlignVal = CGM.getNaturalTypeAlignment(Ty, nullptr, nullptr,
830-
/*ForPointeeType=*/true)
831-
.getAsMaybeAlign();
832-
833-
// The glvalue must be suitably aligned.
834-
if (AlignVal && *AlignVal > llvm::Align(1) &&
835-
(!PtrToAlloca || PtrToAlloca->getAlign() < *AlignVal)) {
836-
PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy);
837-
llvm::Value *Align = Builder.CreateAnd(
838-
PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal->value() - 1));
839-
llvm::Value *Aligned =
840-
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
841-
if (Aligned != True)
842-
Checks.push_back(std::make_pair(Aligned, SanitizerKind::SO_Alignment));
825+
llvm::MaybeAlign AlignVal;
826+
llvm::Value *PtrAsInt = nullptr;
827+
828+
if (SanOpts.has(SanitizerKind::Alignment) &&
829+
!SkippedChecks.has(SanitizerKind::Alignment)) {
830+
AlignVal = Alignment.getAsMaybeAlign();
831+
if (!Ty->isIncompleteType() && !AlignVal)
832+
AlignVal = CGM.getNaturalTypeAlignment(Ty, nullptr, nullptr,
833+
/*ForPointeeType=*/true)
834+
.getAsMaybeAlign();
835+
836+
// The glvalue must be suitably aligned.
837+
if (AlignVal && *AlignVal > llvm::Align(1) &&
838+
(!PtrToAlloca || PtrToAlloca->getAlign() < *AlignVal)) {
839+
PtrAsInt = Builder.CreatePtrToInt(Ptr, IntPtrTy);
840+
llvm::Value *Align = Builder.CreateAnd(
841+
PtrAsInt, llvm::ConstantInt::get(IntPtrTy, AlignVal->value() - 1));
842+
llvm::Value *Aligned =
843+
Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0));
844+
if (Aligned != True)
845+
Checks.push_back(
846+
std::make_pair(Aligned, SanitizerKind::SO_Alignment));
847+
}
843848
}
844-
}
845849

846-
if (Checks.size() > 0) {
847-
llvm::Constant *StaticData[] = {
848-
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty),
849-
llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2(*AlignVal) : 1),
850-
llvm::ConstantInt::get(Int8Ty, TCK)};
851-
EmitCheck(Checks, CheckHandler, StaticData, PtrAsInt ? PtrAsInt : Ptr);
850+
if (Checks.size() > 0) {
851+
llvm::Constant *StaticData[] = {
852+
EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(Ty),
853+
llvm::ConstantInt::get(Int8Ty, AlignVal ? llvm::Log2(*AlignVal) : 1),
854+
llvm::ConstantInt::get(Int8Ty, TCK)};
855+
EmitCheck(Checks, CheckHandler, StaticData, PtrAsInt ? PtrAsInt : Ptr);
856+
}
852857
}
853858

854859
// If possible, check that the vptr indicates that there is a subobject of
@@ -861,6 +866,9 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
861866
// or call a non-static member function
862867
if (SanOpts.has(SanitizerKind::Vptr) &&
863868
!SkippedChecks.has(SanitizerKind::Vptr) && isVptrCheckRequired(TCK, Ty)) {
869+
SanitizerDebugLocation SanScope(this, {SanitizerKind::SO_Vptr},
870+
SanitizerHandler::DynamicTypeCacheMiss);
871+
864872
// Ensure that the pointer is non-null before loading it. If there is no
865873
// compile-time guarantee, reuse the run-time null check or emit a new one.
866874
if (!IsGuaranteedNonNull) {
@@ -929,6 +937,11 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
929937
}
930938

931939
if (Done) {
940+
SanitizerDebugLocation SanScope(
941+
this,
942+
{DoneViaNullSanitize ? SanitizerKind::SO_Null : SanitizerKind::SO_Vptr},
943+
DoneViaNullSanitize ? SanitizerHandler::TypeMismatch
944+
: SanitizerHandler::DynamicTypeCacheMiss);
932945
Builder.CreateBr(Done);
933946
EmitBlock(Done);
934947
}

0 commit comments

Comments
 (0)