18
18
#include " llvm/CodeGen/MachineOperand.h"
19
19
#include " llvm/IR/Constants.h"
20
20
#include " llvm/IR/Metadata.h"
21
+ #include " llvm/IR/Instructions.h"
21
22
#include " llvm/MC/MCAsmInfo.h"
22
23
#include " llvm/MC/MCObjectFileInfo.h"
23
24
#include " llvm/MC/MCStreamer.h"
@@ -41,11 +42,47 @@ void WinCFGuard::endFunction(const MachineFunction *MF) {
41
42
MF->getLongjmpTargets ().end ());
42
43
}
43
44
45
+ // / Returns true if this function's address is escaped in a way that might make
46
+ // / it an indirect call target. Function::hasAddressTaken gives different
47
+ // / results when a function is called directly with a function prototype
48
+ // / mismatch, which requires a cast.
49
+ static bool isPossibleIndirectCallTarget (const Function *F) {
50
+ SmallVector<const Value *, 4 > Users{F};
51
+ while (!Users.empty ()) {
52
+ const Value *FnOrCast = Users.pop_back_val ();
53
+ for (const Use &U : FnOrCast->uses ()) {
54
+ const User *FnUser = U.getUser ();
55
+ if (isa<BlockAddress>(FnUser))
56
+ continue ;
57
+ if (const auto *Call = dyn_cast<CallBase>(FnUser)) {
58
+ if (!Call->isCallee (&U))
59
+ return true ;
60
+ } else if (isa<Instruction>(FnUser)) {
61
+ // Consider any other instruction to be an escape. This has some weird
62
+ // consequences like no-op intrinsics being an escape or a store *to* a
63
+ // function address being an escape.
64
+ return true ;
65
+ } else if (const auto *C = dyn_cast<Constant>(FnUser)) {
66
+ // If this is a constant pointer cast of the function, don't consider
67
+ // this escape. Analyze the uses of the cast as well. This ensures that
68
+ // direct calls with mismatched prototypes don't end up in the CFG
69
+ // table. Consider other constants, such as vtable initializers, to
70
+ // escape the function.
71
+ if (C->stripPointerCasts () == F)
72
+ Users.push_back (FnUser);
73
+ else
74
+ return true ;
75
+ }
76
+ }
77
+ }
78
+ return false ;
79
+ }
80
+
44
81
void WinCFGuard::endModule () {
45
82
const Module *M = Asm->MMI ->getModule ();
46
83
std::vector<const Function *> Functions;
47
84
for (const Function &F : *M)
48
- if (F. hasAddressTaken ( ))
85
+ if (isPossibleIndirectCallTarget (&F ))
49
86
Functions.push_back (&F);
50
87
if (Functions.empty () && LongjmpTargets.empty ())
51
88
return ;
0 commit comments