Skip to content

Commit 3b1fd19

Browse files
committed
[CodeGen] Diagnose and reject non-function ifunc resolvers
Signed-off-by: Itay Bookstein <[email protected]> Reviewed By: MaskRay, erichkeane Differential Revision: https://reviews.llvm.org/D112868
1 parent ce91540 commit 3b1fd19

File tree

2 files changed

+63
-29
lines changed

2 files changed

+63
-29
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -313,21 +313,57 @@ void CodeGenModule::applyGlobalValReplacements() {
313313
// This is only used in aliases that we created and we know they have a
314314
// linear structure.
315315
static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) {
316-
llvm::SmallPtrSet<const llvm::GlobalValue *, 4> Visited;
317-
for (;;) {
318-
if (!GV || !Visited.insert(GV).second)
319-
return nullptr;
320-
321-
const llvm::Constant *C;
322-
if (auto *GA = dyn_cast<llvm::GlobalAlias>(GV))
323-
C = GA->getAliasee();
324-
else if (auto *GI = dyn_cast<llvm::GlobalIFunc>(GV))
325-
C = GI->getResolver();
326-
else
327-
return GV;
316+
const llvm::Constant *C;
317+
if (auto *GA = dyn_cast<llvm::GlobalAlias>(GV))
318+
C = GA->getAliasee();
319+
else if (auto *GI = dyn_cast<llvm::GlobalIFunc>(GV))
320+
C = GI->getResolver();
321+
else
322+
return GV;
323+
324+
const auto *AliaseeGV = dyn_cast<llvm::GlobalValue>(C->stripPointerCasts());
325+
if (!AliaseeGV)
326+
return nullptr;
327+
328+
const llvm::GlobalValue *FinalGV = AliaseeGV->getAliaseeObject();
329+
if (FinalGV == GV)
330+
return nullptr;
331+
332+
return FinalGV;
333+
}
334+
335+
static bool checkAliasedGlobal(DiagnosticsEngine &Diags,
336+
SourceLocation Location, bool IsIFunc,
337+
const llvm::GlobalValue *Alias,
338+
const llvm::GlobalValue *&GV) {
339+
GV = getAliasedGlobal(Alias);
340+
if (!GV) {
341+
Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc;
342+
return false;
343+
}
344+
345+
if (GV->isDeclaration()) {
346+
Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc;
347+
return false;
348+
}
349+
350+
if (IsIFunc) {
351+
// Check resolver function type.
352+
const auto *F = dyn_cast<llvm::Function>(GV);
353+
if (!F) {
354+
Diags.Report(Location, diag::err_alias_to_undefined)
355+
<< IsIFunc << IsIFunc;
356+
return false;
357+
}
328358

329-
GV = dyn_cast<llvm::GlobalValue>(C->stripPointerCasts());
359+
llvm::FunctionType *FTy = F->getFunctionType();
360+
if (!FTy->getReturnType()->isPointerTy()) {
361+
Diags.Report(Location, diag::err_ifunc_resolver_return);
362+
return false;
363+
}
330364
}
365+
366+
return true;
331367
}
332368

333369
void CodeGenModule::checkAliases() {
@@ -344,23 +380,13 @@ void CodeGenModule::checkAliases() {
344380
Location = A->getLocation();
345381
else
346382
llvm_unreachable("Not an alias or ifunc?");
383+
347384
StringRef MangledName = getMangledName(GD);
348385
llvm::GlobalValue *Alias = GetGlobalValue(MangledName);
349-
const llvm::GlobalValue *GV = getAliasedGlobal(Alias);
350-
if (!GV) {
351-
Error = true;
352-
Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc;
353-
} else if (GV->isDeclaration()) {
386+
const llvm::GlobalValue *GV = nullptr;
387+
if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV)) {
354388
Error = true;
355-
Diags.Report(Location, diag::err_alias_to_undefined)
356-
<< IsIFunc << IsIFunc;
357-
} else if (IsIFunc) {
358-
// Check resolver function type.
359-
llvm::FunctionType *FTy = dyn_cast<llvm::FunctionType>(
360-
GV->getType()->getPointerElementType());
361-
assert(FTy);
362-
if (!FTy->getReturnType()->isPointerTy())
363-
Diags.Report(Location, diag::err_ifunc_resolver_return);
389+
continue;
364390
}
365391

366392
llvm::Constant *Aliasee =

clang/test/CodeGen/attr-ifunc.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ void *f1_ifunc();
1313
void f1() __attribute__((ifunc("f1_ifunc")));
1414
// expected-error@-1 {{ifunc must point to a defined function}}
1515

16-
void *f2_a() __attribute__((ifunc("f2_b")));
17-
// expected-error@-1 {{ifunc definition is part of a cycle}}
16+
void *f2_a() __attribute__((alias("f2_b")));
1817
void *f2_b() __attribute__((ifunc("f2_a")));
1918
// expected-error@-1 {{ifunc definition is part of a cycle}}
2019

@@ -27,6 +26,15 @@ void f4_ifunc() {}
2726
void f4() __attribute__((ifunc("f4_ifunc")));
2827
// expected-error@-1 {{ifunc resolver function must return a pointer}}
2928

29+
int f5_resolver_gvar;
30+
void f5() __attribute__((ifunc("f5_resolver_gvar")));
31+
// expected-error@-1 {{ifunc must point to a defined function}}
32+
33+
void *f6_resolver_resolver() { return 0; }
34+
void *f6_resolver() __attribute__((ifunc("f6_resolver_resolver")));
35+
void f6() __attribute__((ifunc("f6_resolver")));
36+
// expected-error@-1 {{ifunc must point to a defined function}}
37+
3038
#else
3139
void f1a() __asm("f1");
3240
void f1a() {}

0 commit comments

Comments
 (0)