forked from OSchip/llvm-project
[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:
parent
ce91540bee
commit
3b1fd19357
|
@ -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 =
|
||||
|
|
|
@ -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() {}
|
||||
|
|
Loading…
Reference in New Issue