Skip to content
Merged
7 changes: 2 additions & 5 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6496,11 +6496,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
SanitizerDebugLocation SanScope(this, {CheckOrdinal}, CheckHandler);
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);

llvm::Metadata *MD;
if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
MD = CGM.CreateMetadataIdentifierGeneralized(QualType(FnType, 0));
else
MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForFnType(QualType(FnType, 0));

llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);

Expand Down
58 changes: 45 additions & 13 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2339,12 +2339,28 @@ llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
return llvm::ConstantInt::get(Int64Ty, llvm::MD5Hash(MDS->getString()));
}

static QualType GeneralizeTransparentUnion(QualType Ty) {
const RecordType *UT = Ty->getAsUnionType();
if (!UT)
return Ty;
const RecordDecl *UD = UT->getOriginalDecl()->getDefinitionOrSelf();
if (!UD->hasAttr<TransparentUnionAttr>())
return Ty;
for (const auto *it : UD->fields()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it intentional to use a range based for loop here only to unconditionally return in the body?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meaning is as intended, I think. Maybe something like if (!UD->fields().empty()) return UD->fields()[0]; would be better style.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, an if statement would signal intent better.

return it->getType();
}
return Ty;
}

// Generalize pointer types to a void pointer with the qualifiers of the
// originally pointed-to type, e.g. 'const char *' and 'char * const *'
// generalize to 'const void *' while 'char *' and 'const char **' generalize to
// 'void *'.
static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
if (!Ty->isPointerType())
static QualType GeneralizeType(ASTContext &Ctx, QualType Ty,
bool GeneralizePointers) {
Ty = GeneralizeTransparentUnion(Ty);

if (!GeneralizePointers || !Ty->isPointerType())
return Ty;

return Ctx.getPointerType(
Expand All @@ -2353,26 +2369,29 @@ static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
}

// Apply type generalization to a FunctionType's return and argument types
static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) {
static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty,
bool GeneralizePointers) {
if (auto *FnType = Ty->getAs<FunctionProtoType>()) {
SmallVector<QualType, 8> GeneralizedParams;
for (auto &Param : FnType->param_types())
GeneralizedParams.push_back(GeneralizeType(Ctx, Param));
GeneralizedParams.push_back(
GeneralizeType(Ctx, Param, GeneralizePointers));

return Ctx.getFunctionType(GeneralizeType(Ctx, FnType->getReturnType()),
GeneralizedParams, FnType->getExtProtoInfo());
return Ctx.getFunctionType(
GeneralizeType(Ctx, FnType->getReturnType(), GeneralizePointers),
GeneralizedParams, FnType->getExtProtoInfo());
}

if (auto *FnType = Ty->getAs<FunctionNoProtoType>())
return Ctx.getFunctionNoProtoType(
GeneralizeType(Ctx, FnType->getReturnType()));
GeneralizeType(Ctx, FnType->getReturnType(), GeneralizePointers));

llvm_unreachable("Encountered unknown FunctionType");
}

llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T, StringRef Salt) {
if (getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
T = GeneralizeFunctionType(getContext(), T);
T = GeneralizeFunctionType(
getContext(), T, getCodeGenOpts().SanitizeCfiICallGeneralizePointers);
if (auto *FnType = T->getAs<FunctionProtoType>())
T = getContext().getFunctionType(
FnType->getReturnType(), FnType->getParamTypes(),
Expand Down Expand Up @@ -3041,9 +3060,13 @@ void CodeGenModule::createFunctionTypeMetadataForIcall(const FunctionDecl *FD,
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
return;

llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
QualType FnType = GeneralizeFunctionType(getContext(), FD->getType(),
/*GeneralizePointers=*/false);
llvm::Metadata *MD = CreateMetadataIdentifierForType(FnType);
F->addTypeMetadata(0, MD);
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
FnType = GeneralizeFunctionType(getContext(), FD->getType(),
/*GeneralizePointers=*/true);
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FnType));

// Emit a hash-based bit set entry for cross-DSO calls.
if (CodeGenOpts.SanitizeCfiCrossDso)
Expand Down Expand Up @@ -7934,6 +7957,15 @@ CodeGenModule::CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
return InternalId;
}

llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForFnType(QualType T) {
assert(isa<FunctionType>(T));
T = GeneralizeFunctionType(
getContext(), T, getCodeGenOpts().SanitizeCfiICallGeneralizePointers);
if (getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
return CreateMetadataIdentifierGeneralized(T);
return CreateMetadataIdentifierForType(T);
}

llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
return CreateMetadataIdentifierImpl(T, MetadataIdMap, "");
}
Expand All @@ -7944,8 +7976,8 @@ CodeGenModule::CreateMetadataIdentifierForVirtualMemPtrType(QualType T) {
}

llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) {
return CreateMetadataIdentifierImpl(GeneralizeFunctionType(getContext(), T),
GeneralizedMetadataIdMap, ".generalized");
return CreateMetadataIdentifierImpl(T, GeneralizedMetadataIdMap,
".generalized");
}

/// Returns whether this module needs the "all-vtables" type identifier.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// Generate a KCFI type identifier for T.
llvm::ConstantInt *CreateKCFITypeId(QualType T, StringRef Salt);

/// Create a metadata identifier for the given function type.
llvm::Metadata *CreateMetadataIdentifierForFnType(QualType T);

/// Create a metadata identifier for the given type. This may either be an
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
/// internal identifiers).
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CodeGen/cfi-icall-generalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,20 @@ void g(int** (*fp)(const char *, const char **)) {
fp(0, 0);
}

union Union {
char *c;
long* n;
} __attribute__((transparent_union));

// CHECK: define{{.*}} void @uni({{.*}} !type [[TYPE2:![0-9]+]] !type [[TYPE2_GENERALIZED:![0-9]+]]
void uni(void (*fn)(union Union), union Union arg1) {
// UNGENERALIZED: call i1 @llvm.type.test(ptr {{.*}}, metadata !"_ZTSFvPcE")
// GENERALIZED: call i1 @llvm.type.test(ptr {{.*}}, metadata !"_ZTSFvPvE.generalized")
fn(arg1);
}

// CHECK: [[TYPE]] = !{i64 0, !"_ZTSFPPiPKcPS2_E"}
// CHECK: [[TYPE_GENERALIZED]] = !{i64 0, !"_ZTSFPvPKvS_E.generalized"}

// CHECK: [[TYPE2]] = !{i64 0, !"_ZTSFvPFv5UnionEPcE"}
// CHECK: [[TYPE2_GENERALIZED]] = !{i64 0, !"_ZTSFvPvS_E.generalized"}
13 changes: 13 additions & 0 deletions clang/test/CodeGen/cfi-icall-normalize2.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
fn(arg1, arg2, arg3);
}

union Union {
char *c;
long* n;
} __attribute__((transparent_union));

void uni(void (*fn)(union Union), union Union arg1) {
// CHECK-LABEL: define{{.*}}uni
// CHECK-SAME: {{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}}
// CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFvPu2i8E.normalized")
fn(arg1);
}

// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFvu3i32ES_E.normalized"}
// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFvu3i32S_ES_S_E.normalized"}
// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFvu3i32S_S_ES_S_S_E.normalized"}
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPFv5UnionEPu2i8E.normalized"}
15 changes: 15 additions & 0 deletions clang/test/CodeGen/kcfi-generalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,23 @@ void g(int** (*fp)(const char *, const char **)) {
fp(0, 0);
}

union Union {
char *c;
long* n;
} __attribute__((transparent_union));

// CHECK: define{{.*}} void @uni({{.*}} !kcfi_type [[TYPE2:![0-9]+]]
void uni(void (*fn)(union Union), union Union arg1) {
// UNGENERALIZED: call {{.*}} [ "kcfi"(i32 -587217045) ]
// GENERALIZED: call {{.*}} [ "kcfi"(i32 2139530422) ]
fn(arg1);
}

// UNGENERALIZED: [[TYPE]] = !{i32 1296635908}
// GENERALIZED: [[TYPE]] = !{i32 -49168686}

// UNGENERALIZED: [[TYPE3]] = !{i32 874141567}
// GENERALIZED: [[TYPE3]] = !{i32 954385378}

// UNGENERALIZED: [[TYPE2]] = !{i32 -1619636625}
// GENERALIZED: [[TYPE2]] = !{i32 -125078496}
19 changes: 17 additions & 2 deletions clang/test/CodeGen/kcfi-normalize.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers -x c++ -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers -o - %s | FileCheck %s --check-prefixes=CHECK,C
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers -x c++ -o - %s | FileCheck %s --check-prefixes=CHECK,CPP
#if !__has_feature(kcfi)
#error Missing kcfi?
#endif
Expand Down Expand Up @@ -28,7 +28,22 @@ void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
fn(arg1, arg2, arg3);
}

union Union {
char *c;
long* n;
} __attribute__((transparent_union));

void uni(void (*fn)(union Union), union Union arg1) {
// CHECK-LABEL: define{{.*}}uni
// CHECK-SAME: {{.*}}!kcfi_type ![[TYPE4:[0-9]+]]
// C: call void %0(ptr %1) [ "kcfi"(i32 1819770848) ]
// CPP: call void %0(ptr %1) [ "kcfi"(i32 -1430221633) ]
fn(arg1);
}

// CHECK: ![[#]] = !{i32 4, !"cfi-normalize-integers", i32 1}
// CHECK: ![[TYPE1]] = !{i32 -1143117868}
// CHECK: ![[TYPE2]] = !{i32 -460921415}
// CHECK: ![[TYPE3]] = !{i32 -333839615}
// C: ![[TYPE4]] = !{i32 -650530463}
// CPP: ![[TYPE4]] = !{i32 1766237188}
Loading