Index: include/llvm/Analysis/ExternalFunctionAnalysis.h =================================================================== --- /dev/null +++ include/llvm/Analysis/ExternalFunctionAnalysis.h @@ -0,0 +1,108 @@ +//=- ExternalFunctionAnalysis.cpp: Find external function pointers -*- C++ -*-// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief A pass that finds incoming external function pointers and finds +/// annotated storage locations and indirect calls based on these locations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_EXTERNALFUNCTIONANALYSIS_H_ +#define LLVM_ANALYSIS_EXTERNALFUNCTIONANALYSIS_H_ + +#include "llvm/Pass.h" + +#include +#include +#include + +namespace llvm { + +class AnalysisUsage; +class CallInst; +class CallSite; +class Function; +class GlobalVariable; +class Instruction; +class StoreInst; +class Value; + +/// A pass that finds external function pointers and related stores and indirect +/// calls. +class ExternalFunctionAnalysis : public ModulePass { + ExternalFunctionAnalysis(const ExternalFunctionAnalysis &) + LLVM_DELETED_FUNCTION; + ExternalFunctionAnalysis &operator=(const ExternalFunctionAnalysis &) + LLVM_DELETED_FUNCTION; + +public: + static char ID; + ExternalFunctionAnalysis() : ModulePass(ID) { + initializeExternalFunctionAnalysisPass(*PassRegistry::getPassRegistry()); + } + + ~ExternalFunctionAnalysis() {} + + bool runOnModule(Module &M); + void getAnalysisUsage(AnalysisUsage &AU) const; + const char *getPassName() const { return "ExternalFunctionAnalysis"; } + + /// Analyzes an instruction to see if it might be an indirect call to an + /// external function pointer. + bool maybeIsExternalCall(Instruction *I) const; + + /// Analyzes a function to see if it was annotated to say it might contain + /// indirect external calls. + bool maybeContainsExternalCall(Function *F) const; + +private: + typedef std::set InstructionSet; + typedef std::set StoreSet; + typedef std::set FunctionSet; + typedef std::map > + StoreSources; + + StoreSet MaybeExternalStores; + FunctionSet MaybeExternalFuns; + InstructionSet MaybeExternalCalls; + + /// Gets indirect call/invoke instructions that came from values that + /// were annotated with __attribute__((annotate("efa-maybe-external"))). + void getMaybeExternalPtrInstrs(Module &M); + + /// Gets indirect call/invoke instructions that came from values that + /// were annotated with __attribute__((annotate("efa-maybe-external"))). Also + /// finds places where values are stored into these variables. + void getMaybeExternalVarInstrs(Module &M); + + /// Gets indirect call/invoked instructions that are in functions that + /// are annotated with __attribute__((annotate("efa-maybe-external"))). Also + /// gets call instructions that flow from annotated global function pointer + /// variables. + void getMaybeExternalFuns(Module &M); + + /// Finds calls to the given GlobalVariable and finds stores into this + /// variable. + void findCalls(GlobalVariable *GV); + + /// Finds call instructions and function types for each call that returns an + /// external function pointer. + void findExternalFunctionPointers(Module &M); + + /// Finds store instructions that flow from a function pointer in the given + /// instruction (and are derived from a call to the given function). + void findFPStores(Function *F, Instruction *I, StoreSources &FPStores); + + /// Walks the chain of uses from a Value and adds any call instructions in + /// chain to the Instrs set. + void findRelatedInstrs(Value *Val); +}; + +ModulePass *createExternalFunctionAnalysisPass(); +} + +#endif /* LLVM_ANALYSIS_EXTERNALFUNCTIONANALYSIS_H_ */ Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -87,6 +87,7 @@ void initializeCFGOnlyViewerPass(PassRegistry&); void initializeCFGPrinterPass(PassRegistry&); void initializeCFGSimplifyPassPass(PassRegistry&); +void initializeExternalFunctionAnalysisPass(PassRegistry&); void initializeFlattenCFGPassPass(PassRegistry&); void initializeStructurizeCFGPass(PassRegistry&); void initializeCFGViewerPass(PassRegistry&); Index: lib/Analysis/Analysis.cpp =================================================================== --- lib/Analysis/Analysis.cpp +++ lib/Analysis/Analysis.cpp @@ -40,6 +40,7 @@ initializeDomViewerPass(Registry); initializeDomPrinterPass(Registry); initializeDomOnlyViewerPass(Registry); + initializeExternalFunctionAnalysisPass(Registry); initializePostDomViewerPass(Registry); initializeDomOnlyPrinterPass(Registry); initializePostDomPrinterPass(Registry); Index: lib/Analysis/CMakeLists.txt =================================================================== --- lib/Analysis/CMakeLists.txt +++ lib/Analysis/CMakeLists.txt @@ -18,6 +18,7 @@ DependenceAnalysis.cpp DomPrinter.cpp DominanceFrontier.cpp + ExternalFunctionAnalysis.cpp IVUsers.cpp InstCount.cpp InstructionSimplify.cpp Index: lib/Analysis/ExternalFunctionAnalysis.cpp =================================================================== --- /dev/null +++ lib/Analysis/ExternalFunctionAnalysis.cpp @@ -0,0 +1,486 @@ +//=- ExternalFunctionAnalysis.cpp: Find external function pointers -*- C++ -*-// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief A pass that finds incoming external function pointers and finds +/// annotated storage locations and indirect calls based on these locations. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "efa" +#include "llvm/Analysis/ExternalFunctionAnalysis.h" + +#include "llvm/ADT/Statistic.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CallSite.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +STATISTIC(NumMaybeExternalCalls, "Number of indirect call sites maybe using" + " external function pointers"); +STATISTIC(NumMaybeExternalStores, "Number of store instructions into annotated" + " locations"); +STATISTIC(NumAnnotatedFunctions, "Number of functions annotated as maybe" + " containing indirect calls to external code"); + +char ExternalFunctionAnalysis::ID = 0; +INITIALIZE_PASS(ExternalFunctionAnalysis, "efa", "ExternalFunctionAnalysis", + true, true) + +const char *efa_annotation = "efa-maybe-external"; + +ModulePass *llvm::createExternalFunctionAnalysisPass() { + return new ExternalFunctionAnalysis(); +} + +// Helper functions + +bool isLLVMExternal(Function *F) { + std::string FunName(F->getName()); + std::string VarAnnotation("llvm.var.annotation"); + std::string PtrAnnotation("llvm.ptr.annotation"); + return ((FunName.compare(0, VarAnnotation.length(), VarAnnotation) == 0) || + (FunName.compare(0, PtrAnnotation.length(), PtrAnnotation) == 0)); +} + +Value *getParameterForArgument(unsigned ArgNo, Function *F) { + unsigned count = 0; + Function::arg_iterator FAI, FAE; + for (FAI = F->arg_begin(), FAE = F->arg_end(); FAI != FAE; ++FAI, ++count) { + if (count == ArgNo) { + Value *Arg = FAI; + return Arg; + } + } + + return NULL; +} + +void followValue(Value *Val, std::list &FoundValues, + std::set &SeenValues) { + if (SeenValues.find(Val) == SeenValues.end()) { + SeenValues.insert(Val); + FoundValues.push_back(Val); + } +} + +void followCall(CallInst *CI, Value::use_iterator VI, Value *Val, + std::list &FoundValues, std::set &SeenValues, + std::set &MaybeExternalCalls) { + CallSite CS(CI); + if (CS.isCallee(VI)) { + MaybeExternalCalls.insert(CI); + ++NumMaybeExternalCalls; + return; + } + + // It must be one of the operands. So, add the operand in the called + // function if this is a direct call to a function defined in this + // module. + Function *CalledFun = CS.getCalledFunction(); + if (!CalledFun) + return; + + if (CalledFun->isDeclaration()) { + if (isLLVMExternal(CalledFun)) { + // An LLVM external like llvm.ptr.annotation or + // llvm.var.annotation is like a cast instruction in effect. + followValue(Val, FoundValues, SeenValues); + } + + return; + } + + if (!CS.hasArgument(Val)) + return; + + unsigned ArgNo = CS.getArgumentNo(VI); + + // This can return NULL if CalledFun is a VarArg function, and the + // argument we want is in the "..." part. + Value *Arg = getParameterForArgument(ArgNo, CalledFun); + if (Arg) { + followValue(Arg, FoundValues, SeenValues); + } +} + +Function *getFunctionParent(Value *Val) { + // Add to the list all the calls to this function. + Instruction *I = dyn_cast(Val); + assert(I && "Couldn't get an instruction from a return value"); + + BasicBlock *BB = I->getParent(); + assert(BB && "Couldn't get the parent of an instruction"); + + Function *ParentFun = BB->getParent(); + assert(ParentFun && "Couldn't get the function parent of a BasicBlock"); + return ParentFun; +} + +void followReturn(Value *Val, std::list &FoundValues, + std::set &SeenValues) { + Function *ParentFun = getFunctionParent(Val); + Function::use_iterator PFI, PFE; + for (PFI = ParentFun->use_begin(), PFE = ParentFun->use_end(); PFI != PFE; + ++PFI) { + Use &PFU = PFI.getUse(); + User *PFUs = PFU.getUser(); + followValue(cast(PFUs), FoundValues, SeenValues); + } +} + +// Member functions + +void ExternalFunctionAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); +} + +void ExternalFunctionAnalysis::findRelatedInstrs(Value *Val) { + // Search all related values and the instructions that use them. This is + // a very restricted data-flow analysis. + + Function *F = getFunctionParent(Val); + std::list Vals; + Vals.push_back(Val); + std::set SeenValues; + SeenValues.insert(Val); + + std::list::iterator VI, VE; + for (VI = Vals.begin(), VE = Vals.end(); VI != VE; ++VI) { + Value *V = *VI; + Value::use_iterator VUI, VUE; + for (VUI = V->use_begin(), VUE = V->use_end(); VUI != VUE; ++VUI) { + Use &U = VUI.getUse(); + User *Us = U.getUser(); + + if (isa(Us) || isa(Us) || + isa(Us)) { + // We only follow instructions that are used as statements, not + // subexpressions of other instructions + if (Instruction *I = dyn_cast(Us)) { + if (isa(I->getParent())) { + followValue(cast(Us), Vals, SeenValues); + } + } + } else if (CallInst *CI = dyn_cast(Us)) { + followCall(CI, VUI, V, Vals, SeenValues, MaybeExternalCalls); + } else if (StoreInst *S = dyn_cast(Us)) { + if (Us->getOperand(0) == V) { + DEBUG(dbgs() << "Warning: in " << F->getName() << " an" + << " efa-maybe-external pointer gets stored into another" + << " pointer.\n"); + } else if (Us->getOperand(1) == V) { + MaybeExternalStores.insert(S); + ++NumMaybeExternalStores; + } + } + } + } +} + +void ExternalFunctionAnalysis::getMaybeExternalPtrInstrs(Module &M) { + Function *PtrAnnotation = M.getFunction("llvm.ptr.annotation.p0i8"); + if (!PtrAnnotation) + return; + + size_t annotation_len = strlen(efa_annotation) + 1; + Value::use_iterator FI, FE; + for (FI = PtrAnnotation->use_begin(), FE = PtrAnnotation->use_end(); FI != FE; + ++FI) { + Use &U = FI.getUse(); + User *Us = U.getUser(); + + // The second operand should say "efa-maybe-external" for this to be the + // right kind of annotation. + Value *OpVal = Us->getOperand(1); + if (!OpVal) + continue; + + Value *V = cast(OpVal)->getOperand(0); + assert(V && "Couldn't get operand 0 of operand 1 of a User"); + + ConstantDataSequential *StrInit = + cast(cast(V)->getInitializer()); + StringRef str = StrInit->getAsString(); + size_t count = str.size(); + if ((count == annotation_len) && + (memcmp(str.data(), efa_annotation, count) == 0)) { + // The llvm.ptr.annotation returns a value that replaces the first arg + Value *VPtr = cast(Us); + findRelatedInstrs(VPtr); + } + } +} + +void ExternalFunctionAnalysis::getMaybeExternalVarInstrs(Module &M) { + Function *VarAnnotation = M.getFunction("llvm.var.annotation"); + if (!VarAnnotation) + return; + + size_t annotation_len = strlen(efa_annotation) + 1; + Value::use_iterator FI, FE; + for (FI = VarAnnotation->use_begin(), FE = VarAnnotation->use_end(); FI != FE; + ++FI) { + Use &U = FI.getUse(); + User *Us = U.getUser(); + + // The second operand should say "efa-maybe-external" for this to be the + // right kind of annotation. + Value *OpVal = Us->getOperand(1); + if (!OpVal) + continue; + + Value *V = cast(OpVal)->getOperand(0); + assert(V && "Couldn't get operand 0 of operand 1 of a User"); + ConstantDataSequential *StrInit = + cast(cast(V)->getInitializer()); + StringRef str = StrInit->getAsString(); + size_t count = str.size(); + if ((count == annotation_len) && + (memcmp(str.data(), efa_annotation, count) == 0)) { + // The llvm.var.annotation does not return a value, but the pointer it + // annotates is its first argument. + User *OpUser = cast(Us->getOperand(0)); + assert(OpUser && "Couldn't get the User for operand 0"); + Value *VPtr = OpUser->getOperand(0); + assert(VPtr && "Couldn't get the second operand 0 for the annotation"); + findRelatedInstrs(VPtr); + } + } +} + +void ExternalFunctionAnalysis::getMaybeExternalFuns(Module &M) { + GlobalVariable *Annotations = M.getNamedGlobal("llvm.global.annotations"); + if (!Annotations) + return; + + size_t annotation_len = strlen(efa_annotation) + 1; + Constant *Init = Annotations->getInitializer(); + assert(Init && "No initializer for global annotations"); + unsigned Count = Init->getNumOperands(); + for (unsigned i = 0; i < Count; ++i) { + Value *V = Init->getOperand(i); + User *U = cast(V); + Value *V2 = U->getOperand(0); + User *U2 = cast(V2); + if (Function *F = dyn_cast(U2->getOperand(0))) { + + User *StrUser = cast(U->getOperand(1)); + assert(StrUser && "Couldn't get operand 1 for the annotation"); + Value *StrV = StrUser->getOperand(0); + assert(StrV && "Couldn't get the value for the annotation"); + ConstantDataSequential *StrInit = cast( + cast(StrV)->getInitializer()); + assert(StrInit && "Couldn't get the string initializer for annotation"); + StringRef str = StrInit->getAsString(); + size_t count = str.size(); + if ((count == annotation_len) && + (memcmp(str.data(), efa_annotation, count) == 0)) { + MaybeExternalFuns.insert(F); + ++NumAnnotatedFunctions; + } + } else if (GlobalVariable *GV = + dyn_cast(U2->getOperand(0))) { + // Only look at this global variable if it is of pointer type. + Type *GVT = GV->getType(); + if (isa(GVT)) { + findCalls(GV); + } + } + } +} + +void ExternalFunctionAnalysis::findCalls(GlobalVariable *GV) { + GlobalVariable::use_iterator GVI, GVE; + for (GVI = GV->use_begin(), GVE = GV->use_end(); GVI != GVE; ++GVI) { + Use &GU = GVI.getUse(); + User *GUs = GU.getUser(); + Value *V = cast(GUs); + + // For store instructions, the global variable can be used directly. + if (StoreInst *VS = dyn_cast(V)) { + Value *P = VS->getPointerOperand(); + if (P == GV) { + MaybeExternalStores.insert(VS); + ++NumMaybeExternalStores; + } + } + std::list FoundValues; + FoundValues.push_back(V); + std::set SeenValues; + SeenValues.insert(V); + + std::list::iterator FI, FE; + for (FI = FoundValues.begin(), FE = FoundValues.end(); FI != FE; ++FI) { + Value::use_iterator VI, VE; + for (VI = (*FI)->use_begin(), VE = (*FI)->use_end(); VI != VE; ++VI) { + Use &U = VI.getUse(); + User *Us = U.getUser(); + Value *Val = cast(Us); + if (isa(Val)) { + followValue(Val, FoundValues, SeenValues); + } else if (isa(Val)) { + followReturn(Val, FoundValues, SeenValues); + } else if (CallInst *CI = dyn_cast(Val)) { + followCall(CI, VI, *FI, FoundValues, SeenValues, MaybeExternalCalls); + } else if (StoreInst *S = dyn_cast(Val)) { + // If it's storing into this variable, then mark this store as a safe + // store. + Value *P = S->getPointerOperand(); + if (P == *FI) { + MaybeExternalStores.insert(S); + ++NumMaybeExternalStores; + } + } + } + } + } +} + +void ExternalFunctionAnalysis::findFPStores(Function *F, Instruction *I, + StoreSources &FPStores) { + std::list FoundValues; + FoundValues.push_back(I); + std::set SeenValues; + SeenValues.insert(I); + + std::list::iterator FI, FE; + Function *CallerFun = getFunctionParent(I); + + for (FI = FoundValues.begin(), FE = FoundValues.end(); FI != FE; ++FI) { + Value::use_iterator VI, VE; + for (VI = (*FI)->use_begin(), VE = (*FI)->use_end(); VI != VE; ++VI) { + Use &U = VI.getUse(); + User *Us = U.getUser(); + Value *Val = cast(Us); + if (isa(Val)) { + followValue(Val, FoundValues, SeenValues); + } else if (isa(Val)) { + followReturn(Val, FoundValues, SeenValues); + } else if (StoreInst *S = dyn_cast(Val)) { + Value *P = S->getPointerOperand(); + Type *OpTy = P->getType(); + PointerType *PPTy = dyn_cast(OpTy); + if (!PPTy) + continue; + + Type *PElementTy = PPTy->getElementType(); + PointerType *PTy = dyn_cast(PElementTy); + if (!PTy) + continue; + + Type *ElementTy = PTy->getElementType(); + if (isa(ElementTy)) { + FPStores[S].first = F; + FPStores[S].second = CallerFun; + } + } else if (CallInst *CI = dyn_cast(Val)) { + followCall(CI, VI, *FI, FoundValues, SeenValues, MaybeExternalCalls); + } + } + } +} +bool ExternalFunctionAnalysis::runOnModule(Module &M) { + // Build up the sets of maybe-external functions, variables, pointers, and + // their associated indirect calls and stores by looking for incoming external + // function pointers and tracing both their dataflow and dataflow from + // annotated storage locations. + getMaybeExternalFuns(M); + getMaybeExternalVarInstrs(M); + getMaybeExternalPtrInstrs(M); + + // Find function pointers returned from external functions. + findExternalFunctionPointers(M); + + return true; +} + +// For each call site of an external function that returns a pointer, trace this +// value up to see if it is ever cast to a function pointer and stored. +void ExternalFunctionAnalysis::findExternalFunctionPointers(Module &M) { + // Walk through the set of functions looking for ones that return pointers. + // The first function in FPStores is the external function that originally + // generated the external pointer, and the second function is the function in + // which the call to the first function took place. + std::string New("_Znwm"); + StoreSources FPStores; + Module::iterator MI, ME; + for (MI = M.begin(), ME = M.end(); MI != ME; ++MI) { + Function *F = MI; + + // We only follow calls to external pointers. + GlobalValue *GV = cast(F); + if (!GV->isDeclaration()) + continue; + + // We don't follow calls to llvm annotation functions + if (isLLVMExternal(F)) + continue; + + // Don't chase values from operator new. + std::string Name(F->getName()); + if (Name.compare(0, New.length(), New) == 0) + continue; + + // Make sure this external function returns a pointer type. + FunctionType *FT = F->getFunctionType(); + Type *RT = FT->getReturnType(); + if (!isa(RT)) + continue; + DEBUG(dbgs() << "External function '" << F->getName() + << "' returns a pointer\n"); + + Function::use_iterator FI, FE; + for (FI = F->use_begin(), FE = F->use_end(); FI != FE; ++FI) { + Use &U = FI.getUse(); + User *Us = U.getUser(); + + Instruction *I = dyn_cast(Us); + if (!I) + continue; + + // Only trace uses of direct calls. + CallSite CS(I); + if ((CS.isCall() || CS.isInvoke()) && CS.getCalledFunction()) { + findFPStores(F, I, FPStores); + } + } + } + + std::map >::iterator SI, SE; + for (SI = FPStores.begin(), SE = FPStores.end(); SI != SE; ++SI) { + // Is the storage location annotated with efa-maybe-external? If not, then + // complain. + if (MaybeExternalStores.find(SI->first) != MaybeExternalStores.end()) + continue; + + Function *ParentFun = getFunctionParent(SI->first); + if (!maybeContainsExternalCall(ParentFun)) { + errs() << "A store instruction in " << ParentFun->getName() + << " is storing an external function pointer derived from a call" + << " to " << SI->second.first->getName() << " in the function " + << SI->second.second->getName() << " but is not annotated with" + << " efa-maybe-external\n"; + } + } +} + +bool ExternalFunctionAnalysis::maybeIsExternalCall(Instruction *I) const { + return MaybeExternalCalls.find(I) != MaybeExternalCalls.end(); +} + +bool ExternalFunctionAnalysis::maybeContainsExternalCall(Function *F) const { + return MaybeExternalFuns.find(F) != MaybeExternalFuns.end(); +} Index: test/Analysis/ExternalFunctionAnalysis/external_function_analysis.ll =================================================================== --- /dev/null +++ test/Analysis/ExternalFunctionAnalysis/external_function_analysis.ll @@ -0,0 +1,170 @@ +; RUN: llvm-as < %s >%t1 +; RUN: opt -efa -o %t2 %t1 -stats -debug-only=efa 2>&1 | FileCheck %s + +target triple = "x86_64-unknown-linux-gnu" + +@.str1 = private unnamed_addr constant [17 x i8] c"external_call.ll\00", section "llvm.metadata" +@.str2 = private unnamed_addr constant [19 x i8] c"efa-maybe-external\00", section "llvm.metadata" +@fff = internal global i32 (...)* null, align 8 +@llvm.global.annotations = appending global [3 x { i8*, i8*, i8*, i32 }] [{ i8*, i8*, i8*, i32 } { i8* bitcast (i32 (...)** @fff to i8*), i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 19 }, { i8*, i8*, i8*, i32 } { i8* bitcast (void ()* @known_external_call_fun to i8*), i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 19 }, { i8*, i8*, i8*, i32 } { i8* bitcast (void ()* @known_external_call_fun to i8*), i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 19 }], section "llvm.metadata" + +%struct.fun_struct = type { i32 (...)* } +@sfs = internal global %struct.fun_struct zeroinitializer, align 8 + +define internal i32 (...)* @g() { +entry: + %call = call i32 (...)* (...)* @f() + ret i32 (...)* %call +} + +declare i32 (...)* @f(...) +declare i8* (...)* @f2(...) +declare void @indirect_fun() +declare void ()* @get_fun() + +define i32 @m(void ()* %fun) { + call void ()* %fun() + ret i32 0 +} + +define i32 @m_no_rewrite(void ()* %fun) { + call void ()* %fun() + ret i32 0 +} + +define void @retfun() { + ret void +} + +declare void @llvm.var.annotation(i8*, i8*, i8*, i32) +declare i8* @llvm.ptr.annotation.p0i8(i8*, i8*, i8*, i32) + +define i32 @call_ext_fun() { + %f = call void ()* ()* @get_fun() + %a = call i32 @m(void ()* %f) + ret i32 %a +} + +; Check the case of storing into an annotated variable +define void @var_annotation() { + %h = alloca i32 (...)*, align 8 + %h1 = bitcast i32 (...)** %h to i8* + call void @llvm.var.annotation(i8* %h1, i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 25) + %call = call i32 (...)* ()* @g() + store i32 (...)* %call, i32 (...)** %h, align 8 + ret void +} + +; Check the case of storing into an annotated struct member +define void @struct_annotation() { + %fs = alloca %struct.fun_struct, align 8 + %call = call i8* (...)* (...)* @f2() + %1 = bitcast i8* (...)* %call to i32 (...)* + %v = getelementptr inbounds %struct.fun_struct* %fs, i32 0, i32 0 + %2 = bitcast i32 (...)** %v to i8* + %3 = call i8* @llvm.ptr.annotation.p0i8(i8* %2, i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 10) + %4 = bitcast i8* %3 to i32 (...)** + store i32 (...)* %1, i32 (...)** %4, align 8 + ret void +} + +; Check the case of storing into part of an annotated structure +define void @struct_annotation_through_GEP() { + %fs = alloca %struct.fun_struct, align 8 + %fs.v = bitcast %struct.fun_struct* %fs to i8* + %1 = call i8* @llvm.ptr.annotation.p0i8(i8* %fs.v, i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 10) + %2 = bitcast i8* %1 to %struct.fun_struct* + %call = call i8* (...)* (...)* @f2() + %call.cast = bitcast i8* (...)* %call to i32 (...)* + %v = getelementptr inbounds %struct.fun_struct* %2, i32 0, i32 0 + store i32 (...)* %call.cast, i32 (...)** %v, align 8 + ret void +} + +; Check the case of storing into a non-annotated struct member +define void @struct_non_annotation() { + %fs = alloca %struct.fun_struct, align 8 + %call = call i8* (...)* (...)* @f2() + %1 = bitcast i8* (...)* %call to i32 (...)* + %v = getelementptr inbounds %struct.fun_struct* %fs, i32 0, i32 0 + store i32 (...)* %1, i32 (...)** %v, align 8 + ret void +} + +; Check the case of calling a value from an annotated struct member +define void @call_struct_annotation() { + %fs = alloca %struct.fun_struct, align 8 + %v = getelementptr inbounds %struct.fun_struct* %fs, i32 0, i32 0 + %1 = bitcast i32 (...)** %v to i8* + %2 = call i8* @llvm.ptr.annotation.p0i8(i8* %1, i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 10) + %3 = bitcast i8* %2 to i32 (...)** + %4 = load i32 (...)** %3, align 8 + %rv = call i32 (...)* %4() + ret void +} + +define i32 (...)* @transitive_ext_fun() { + %f = call i32 (...)* (...)* @f() + %b = bitcast i32 (...)* %f to i8* + %a = bitcast i8* %b to i32 (...)* + ret i32 (...)* %f +} + +define i32 (...)* @transitive_return_fun(i32 (...)* %in) { + %b = bitcast i32 (...)* %in to i8* + %a = bitcast i8* %b to i32 (...)* + ret i32 (...)* %a +} + +; Check the case of storing into an annotated variable +define void @transitive_pointer_detection() { + %h = alloca i32 (...)*, align 8 + %h1 = bitcast i32 (...)** %h to i8* + call void @llvm.var.annotation(i8* %h1, i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 25) + %call = call i32 (...)* ()* @transitive_ext_fun() + store i32 (...)* %call, i32 (...)** %h, align 8 + ret void +} + +; Check the case of storing into an annotated variable +define void @transitive_return_detection() { + %h = alloca i32 (...)*, align 8 + %h1 = bitcast i32 (...)** %h to i8* + call void @llvm.var.annotation(i8* %h1, i8* getelementptr inbounds ([19 x i8]* @.str2, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 25) + %f = call i32 (...)* (...)* @f() + %call = call i32 (...)* (i32 (...)*)* @transitive_return_fun(i32 (...)* %f) + store i32 (...)* %call, i32 (...)** %h, align 8 + ret void +} + +; Check the case of storing into an annotated variable +define void @var_non_annotation() { + %h = alloca i32 (...)*, align 8 + %call = call i32 (...)* ()* @g() + store i32 (...)* %call, i32 (...)** %h, align 8 + ret void +} + +define void @known_external_call_fun() { + %h = alloca i32 (...)*, align 8 + %call = call i32 (...)* ()* @g() + store i32 (...)* %call, i32 (...)** %h, align 8 + ret void +} + +declare i8* @composite_pointer_external() +define void @call_through_GEP() { + + ret void +} + +; XFAIL: win32 +; CHECK: External function 'f' returns a pointer +; CHECK: External function 'f2' returns a pointer +; CHECK: External function 'get_fun' returns a pointer +; CHECK-NOT: A store instruction in struct_annotation_through_GEP is storing an external function pointer derived from a call to f2 in the function struct_annotation_through_GEP +; CHECK: A store instruction in struct_non_annotation is storing an external function pointer derived from a call to f2 in the function struct_non_annotation +; CHECK: A store instruction in var_non_annotation is storing an external function pointer derived from a call to f in the function g +; CHECK-NOT: A store instruction in known_external_call_fun is storing an external function pointer derived from a call to f in the function g +; CHECK: 2 efa - Number of indirect call sites maybe using external function pointers +; CHECK: 5 efa - Number of store instructions into annotated locations