[CodeGen] Diagnose and reject non-function ifunc resolvers

Signed-off-by: Itay Bookstein <ibookstein@gmail.com>

Reviewed By: MaskRay, erichkeane

Differential Revision: https://reviews.llvm.org/D112868
This commit is contained in:
Itay Bookstein 2021-10-30 14:27:38 +03:00
parent ce91540bee
commit 3b1fd19357
2 changed files with 62 additions and 28 deletions

View File

@ -313,21 +313,57 @@ void CodeGenModule::applyGlobalValReplacements() {
// This is only used in aliases that we created and we know they have a
// linear structure.
static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) {
llvm::SmallPtrSet<const llvm::GlobalValue *, 4> Visited;
for (;;) {
if (!GV || !Visited.insert(GV).second)
return nullptr;
const llvm::Constant *C;
if (auto *GA = dyn_cast<llvm::GlobalAlias>(GV))
C = GA->getAliasee();
else if (auto *GI = dyn_cast<llvm::GlobalIFunc>(GV))
C = GI->getResolver();
else
return GV;
const llvm::Constant *C;
if (auto *GA = dyn_cast<llvm::GlobalAlias>(GV))
C = GA->getAliasee();
else if (auto *GI = dyn_cast<llvm::GlobalIFunc>(GV))
C = GI->getResolver();
else
return GV;
const auto *AliaseeGV = dyn_cast<llvm::GlobalValue>(C->stripPointerCasts());
if (!AliaseeGV)
return nullptr;
GV = dyn_cast<llvm::GlobalValue>(C->stripPointerCasts());
const llvm::GlobalValue *FinalGV = AliaseeGV->getAliaseeObject();
if (FinalGV == GV)
return nullptr;
return FinalGV;
}
static bool checkAliasedGlobal(DiagnosticsEngine &Diags,
SourceLocation Location, bool IsIFunc,
const llvm::GlobalValue *Alias,
const llvm::GlobalValue *&GV) {
GV = getAliasedGlobal(Alias);
if (!GV) {
Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc;
return false;
}
if (GV->isDeclaration()) {
Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc;
return false;
}
if (IsIFunc) {
// Check resolver function type.
const auto *F = dyn_cast<llvm::Function>(GV);
if (!F) {
Diags.Report(Location, diag::err_alias_to_undefined)
<< IsIFunc << IsIFunc;
return false;
}
llvm::FunctionType *FTy = F->getFunctionType();
if (!FTy->getReturnType()->isPointerTy()) {
Diags.Report(Location, diag::err_ifunc_resolver_return);
return false;
}
}
return true;
}
void CodeGenModule::checkAliases() {
@ -344,23 +380,13 @@ void CodeGenModule::checkAliases() {
Location = A->getLocation();
else
llvm_unreachable("Not an alias or ifunc?");
StringRef MangledName = getMangledName(GD);
llvm::GlobalValue *Alias = GetGlobalValue(MangledName);
const llvm::GlobalValue *GV = getAliasedGlobal(Alias);
if (!GV) {
const llvm::GlobalValue *GV = nullptr;
if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV)) {
Error = true;
Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc;
} else if (GV->isDeclaration()) {
Error = true;
Diags.Report(Location, diag::err_alias_to_undefined)
<< IsIFunc << IsIFunc;
} else if (IsIFunc) {
// Check resolver function type.
llvm::FunctionType *FTy = dyn_cast<llvm::FunctionType>(
GV->getType()->getPointerElementType());
assert(FTy);
if (!FTy->getReturnType()->isPointerTy())
Diags.Report(Location, diag::err_ifunc_resolver_return);
continue;
}
llvm::Constant *Aliasee =

View File

@ -13,8 +13,7 @@ void *f1_ifunc();
void f1() __attribute__((ifunc("f1_ifunc")));
// expected-error@-1 {{ifunc must point to a defined function}}
void *f2_a() __attribute__((ifunc("f2_b")));
// expected-error@-1 {{ifunc definition is part of a cycle}}
void *f2_a() __attribute__((alias("f2_b")));
void *f2_b() __attribute__((ifunc("f2_a")));
// expected-error@-1 {{ifunc definition is part of a cycle}}
@ -27,6 +26,15 @@ void f4_ifunc() {}
void f4() __attribute__((ifunc("f4_ifunc")));
// expected-error@-1 {{ifunc resolver function must return a pointer}}
int f5_resolver_gvar;
void f5() __attribute__((ifunc("f5_resolver_gvar")));
// expected-error@-1 {{ifunc must point to a defined function}}
void *f6_resolver_resolver() { return 0; }
void *f6_resolver() __attribute__((ifunc("f6_resolver_resolver")));
void f6() __attribute__((ifunc("f6_resolver")));
// expected-error@-1 {{ifunc must point to a defined function}}
#else
void f1a() __asm("f1");
void f1a() {}