summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp39
1 files changed, 38 insertions, 1 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp b/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
index f071a2583e5..914308d9147 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp
@@ -18,6 +18,7 @@
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCStreamer.h"
@@ -41,11 +42,47 @@ void WinCFGuard::endFunction(const MachineFunction *MF) {
MF->getLongjmpTargets().end());
}
+/// Returns true if this function's address is escaped in a way that might make
+/// it an indirect call target. Function::hasAddressTaken gives different
+/// results when a function is called directly with a function prototype
+/// mismatch, which requires a cast.
+static bool isPossibleIndirectCallTarget(const Function *F) {
+ SmallVector<const Value *, 4> Users{F};
+ while (!Users.empty()) {
+ const Value *FnOrCast = Users.pop_back_val();
+ for (const Use &U : FnOrCast->uses()) {
+ const User *FnUser = U.getUser();
+ if (isa<BlockAddress>(FnUser))
+ continue;
+ if (const auto *Call = dyn_cast<CallBase>(FnUser)) {
+ if (!Call->isCallee(&U))
+ return true;
+ } else if (isa<Instruction>(FnUser)) {
+ // Consider any other instruction to be an escape. This has some weird
+ // consequences like no-op intrinsics being an escape or a store *to* a
+ // function address being an escape.
+ return true;
+ } else if (const auto *C = dyn_cast<Constant>(FnUser)) {
+ // If this is a constant pointer cast of the function, don't consider
+ // this escape. Analyze the uses of the cast as well. This ensures that
+ // direct calls with mismatched prototypes don't end up in the CFG
+ // table. Consider other constants, such as vtable initializers, to
+ // escape the function.
+ if (C->stripPointerCasts() == F)
+ Users.push_back(FnUser);
+ else
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void WinCFGuard::endModule() {
const Module *M = Asm->MMI->getModule();
std::vector<const Function *> Functions;
for (const Function &F : *M)
- if (F.hasAddressTaken())
+ if (isPossibleIndirectCallTarget(&F))
Functions.push_back(&F);
if (Functions.empty() && LongjmpTargets.empty())
return;
OpenPOWER on IntegriCloud