blob: 556df5dc3df0fb043c106672d0ecd3ab7e663069 [file] [log] [blame]
//===------------ TypeChecks.cpp - Insert runtime type checks -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass inserts checks to enforce type safety during runtime.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "type-checks"
#include "assistDS/TypeChecks.h"
#include "llvm/IR/Constants.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/ADT/Statistic.h"
#include <set>
#include <vector>
#include <deque>
using namespace llvm;
char TypeChecks::ID = 0;
static RegisterPass<TypeChecks>
TC("typechecks", "Insert runtime type checks", false, true);
// Pass statistics
STATISTIC(numLoadChecks, "Number of Load Insts that need type checks");
STATISTIC(numStoreChecks, "Number of Store Insts that need type checks");
STATISTIC(numTypes, "Number of Types used in the module");
namespace {
static cl::opt<bool> EnablePointerTypeChecks("enable-ptr-type-checks",
cl::desc("Distinguish pointer types in loads"),
cl::Hidden,
cl::init(false));
static cl::opt<bool> DisablePtrCmpChecks("no-ptr-cmp-checks",
cl::desc("Dont instrument cmp statements"),
cl::Hidden,
cl::init(false));
static cl::opt<bool> TrackAllLoads("track-all-loads",
cl::desc("Check at all loads irrespective of use"),
cl::Hidden,
cl::init(false));
}
static int tagCounter = 0;
static Type *VoidTy = 0;
static Type *Int8Ty = 0;
static Type *Int32Ty = 0;
static Type *Int64Ty = 0;
static PointerType *VoidPtrTy = 0;
static Type *TypeTagTy = 0;
static Type *TypeTagPtrTy = 0;
static Constant *One = 0;
static Constant *Zero = 0;
static Constant *RegisterArgv;
static Constant *RegisterEnvp;
static Constant *trackGlobal;
static Constant *trackStoreInst;
static Constant *trackStringInput;
static Constant *trackArray;
static Constant *trackInitInst;
static Constant *trackUnInitInst;
static Constant *getTypeTag;
static Constant *checkTypeInst;
static Constant *copyTypeInfo;
static Constant *setTypeInfo;
static Constant *setVAInfo;
static Constant *copyVAInfo;
static Constant *checkVAArg;
unsigned int TypeChecks::getTypeMarker(Type * Ty) {
if(!EnablePointerTypeChecks) {
if(Ty->isPointerTy()) {
Ty = VoidPtrTy;
}
}
if(UsedTypes.find(Ty) == UsedTypes.end())
UsedTypes[Ty] = UsedTypes.size();
assert((UsedTypes.size() < 254) && "Too many types found. Not enough metadata bits");
return UsedTypes[Ty];
}
unsigned int TypeChecks::getTypeMarker(Value *V) {
return getTypeMarker(V->getType());
}
unsigned int TypeChecks::getSize(Type *Ty) {
return TD->getTypeStoreSize(Ty);
}
Constant *TypeChecks::getSizeConstant(Type *Ty) {
return (ConstantInt::get(Int64Ty, getSize(Ty)));
}
static Constant *getTagCounter() {
return ConstantInt::get(Int32Ty, tagCounter++);
}
Constant *TypeChecks::getTypeMarkerConstant(Value * V) {
return ConstantInt::get(TypeTagTy, getTypeMarker(V));
}
Constant *TypeChecks::getTypeMarkerConstant(Type *T) {
return ConstantInt::get(TypeTagTy, getTypeMarker(T));
}
static inline Value *
castTo (Value * V, Type * Ty, std::string Name, Instruction * InsertPt) {
//
// Don't bother creating a cast if it's already the correct type.
//
if (V->getType() == Ty)
return V;
//
// If it's a constant, just create a constant expression.
//
if (Constant * C = dyn_cast<Constant>(V)) {
Constant * CE = ConstantExpr::getZExtOrBitCast (C, Ty);
return CE;
}
//
// Otherwise, insert a cast instruction.
//
return CastInst::CreateZExtOrBitCast (V, Ty, Name, InsertPt);
}
bool TypeChecks::runOnModule(Module &M) {
bool modified = false; // Flags whether we modified the module.
bool transformIndirectCalls = true;
TD = &getAnalysis<DataLayoutPass>().getDataLayout();
addrAnalysis = &getAnalysis<AddressTakenAnalysis>();
// Create the necessary prototypes
VoidTy = IntegerType::getVoidTy(M.getContext());
Int8Ty = IntegerType::getInt8Ty(M.getContext());
Int32Ty = IntegerType::getInt32Ty(M.getContext());
Int64Ty = IntegerType::getInt64Ty(M.getContext());
VoidPtrTy = PointerType::getUnqual(Int8Ty);
TypeTagTy = Int8Ty;
TypeTagPtrTy = PointerType::getUnqual(TypeTagTy);
One = ConstantInt::get(Int64Ty, 1);
Zero = ConstantInt::get(Int64Ty, 0);
// Add prototypes for the dynamic type checking functions
initRuntimeCheckPrototypes(M);
UsedTypes.clear(); // Reset if run multiple times.
VAArgFunctions.clear();
ByValFunctions.clear();
AddressTakenFunctions.clear();
// Only works for whole program analysis
Function *MainF = M.getFunction("main");
if (MainF == 0 || MainF->isDeclaration()) {
assert(0 && "No main function found");
return false;
}
// Insert the shadow initialization function.
modified |= initShadow(M);
// Record argv/envp
modified |= visitMain(M, *MainF);
// Recognize special cases
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
Function &F = *MI;
if(F.isDeclaration()) {
if(addrAnalysis->hasAddressTaken(&F))
transformIndirectCalls = false;
continue;
}
std::string name = F.getName();
if (strncmp(name.c_str(), "tc.", 3) == 0) continue;
if (strncmp(name.c_str(), "main", 4) == 0) continue;
// Iterate and find all byval functions
bool hasByValArg = false;
for (Function::arg_iterator I = F.arg_begin(); I != F.arg_end(); ++I) {
if (I->hasByValAttr()) {
hasByValArg = true;
break;
}
}
if(hasByValArg) {
ByValFunctions.push_back(&F);
}
// Iterate and find all address taken functions
if(addrAnalysis->hasAddressTaken(&F)) {
AddressTakenFunctions.push_back(&F);
}
// Iterate and find all varargs functions
if(F.isVarArg()) {
VAArgFunctions.push_back(&F);
continue;
}
}
// Modify all byval functions
while(!ByValFunctions.empty()) {
Function *F = ByValFunctions.back();
ByValFunctions.pop_back();
modified |= visitByValFunction(M, *F);
}
// Modify all the var arg functions
while(!VAArgFunctions.empty()) {
Function *F = VAArgFunctions.back();
VAArgFunctions.pop_back();
assert(F->isVarArg());
modified |= visitVarArgFunction(M, *F);
}
// Modify all the address taken functions
if(transformIndirectCalls) {
while(!AddressTakenFunctions.empty()) {
Function *F = AddressTakenFunctions.back();
AddressTakenFunctions.pop_back();
if(F->isVarArg())
continue;
visitAddressTakenFunction(M, *F);
}
}
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
Function &F = *MI;
if(F.isDeclaration())
continue;
DominatorTree & DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
std::deque<DomTreeNode *> Worklist;
Worklist.push_back (DT.getRootNode());
while(Worklist.size()) {
DomTreeNode * Node = Worklist.front();
Worklist.pop_front();
BasicBlock *BB = Node->getBlock();
for (BasicBlock::iterator bi = BB->begin(); bi != BB->end(); ++bi) {
Instruction &I = *bi;
if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
modified |= visitStoreInst(M, *SI);
} else if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
modified |= visitLoadInst(M, *LI);
} else if (CallInst *CI = dyn_cast<CallInst>(&I)) {
modified |= visitCallInst(M, *CI);
} else if (InvokeInst *II = dyn_cast<InvokeInst>(&I)) {
modified |= visitInvokeInst(M, *II);
} else if (AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
modified |= visitAllocaInst(M, *AI);
} else if (VAArgInst *VI = dyn_cast<VAArgInst>(&I)) {
modified |= visitVAArgInst(M, *VI);
}
}
Worklist.insert(Worklist.end(), Node->begin(), Node->end());
}
// Loop over all of the instructions in the function,
// adding instrumentation where needed.
/*for (inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE;++II) {
Instruction &I = *II;
if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
modified |= visitStoreInst(M, *SI);
} else if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
modified |= visitLoadInst(M, *LI);
} else if (CallInst *CI = dyn_cast<CallInst>(&I)) {
modified |= visitCallInst(M, *CI);
} else if (InvokeInst *II = dyn_cast<InvokeInst>(&I)) {
modified |= visitInvokeInst(M, *II);
} else if (AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
modified |= visitAllocaInst(M, *AI);
} else if (VAArgInst *VI = dyn_cast<VAArgInst>(&I)) {
modified |= visitVAArgInst(M, *VI);
}
}*/
}
// visit all the indirect call sites
if(transformIndirectCalls) {
std::set<Instruction*>::iterator II = IndCalls.begin();
for(; II != IndCalls.end();) {
Instruction *I = *II++;
modified |= visitIndirectCallSite(M,I);
}
}
// visit all the uses of the address taken functions and var arg functions and modify if
// not being passed to external code
std::map<Function *, Function * >::iterator FI = IndFunctionsMap.begin(), FE = IndFunctionsMap.end();
for(;FI!=FE;++FI) {
Function *F = FI->first;
Constant *CNew = ConstantExpr::getBitCast(FI->second, F->getType());
std::set<User *> toReplace;
for(Function::user_iterator User = F->user_begin();
User != F->user_end();++User) {
toReplace.insert(*User);
}
for(std::set<llvm::User *>::iterator userI = toReplace.begin(); userI != toReplace.end(); ++userI) {
llvm::User * user = *userI;
if(Constant *C = dyn_cast<Constant>(user)) {
if(!isa<GlobalValue>(C)) {
bool changeUse = true;
for(Value::user_iterator II = user->user_begin();
II != user->user_end(); II++) {
if(CallInst *CI = dyn_cast<CallInst>(*II))
if(CI->getCalledFunction()) {
if(CI->getCalledFunction()->isDeclaration())
changeUse = false;
}
}
if(!changeUse)
continue;
std::vector<Use *> ReplaceWorklist;
for (User::op_iterator use = user->op_begin();
use != user->op_end();
++use) {
if (use->get() == F) {
ReplaceWorklist.push_back (use);
}
}
//
// Do replacements in the worklist.
// Special case for ContantArray(triggered by 253.perl)
// ConstantArray::replaceUsesOfWithOnConstant, replace all uses
// in that constant, unlike the other versions, which only
// replace the use specified in ReplaceWorklist.
//
if(isa<ConstantArray>(C)) {
C->replaceUsesOfWithOnConstant(F, CNew, ReplaceWorklist[0]);
} else {
for (unsigned index = 0; index < ReplaceWorklist.size(); ++index) {
C->replaceUsesOfWithOnConstant(F, CNew, ReplaceWorklist[index]);
}
}
continue;
}
}
if(CallInst *CI = dyn_cast<CallInst>(user)) {
if(CI->getCalledFunction()) {
if(CI->getCalledFunction()->isDeclaration())
continue;
}
}
user->replaceUsesOfWith(F, CNew);
}
}
// remove redundant checks, caused due to insturmenting uses of loads
// Remove a check if it is dominated by another check for the same instruction
optimizeChecks(M);
// add a global that contains the mapping from metadata to strings
addTypeMap(M);
// Update stats
numTypes += UsedTypes.size();
return modified;
}
void TypeChecks::initRuntimeCheckPrototypes(Module &M) {
RegisterArgv = M.getOrInsertFunction("trackArgvType",
VoidTy,
Int32Ty, /*argc */
VoidPtrTy->getPointerTo(),/*argv*/
NULL);
RegisterEnvp = M.getOrInsertFunction("trackEnvpType",
VoidTy,
VoidPtrTy->getPointerTo(),/*envp*/
NULL);
trackGlobal = M.getOrInsertFunction("trackGlobal",
VoidTy,
VoidPtrTy,/*ptr*/
TypeTagTy,/*type*/
Int64Ty,/*size*/
Int32Ty,/*tag*/
NULL);
trackArray = M.getOrInsertFunction("trackArray",
VoidTy,
VoidPtrTy,/*ptr*/
Int64Ty,/*size*/
Int64Ty,/*count*/
Int32Ty,/*tag*/
NULL);
trackInitInst = M.getOrInsertFunction("trackInitInst",
VoidTy,
VoidPtrTy,/*ptr*/
Int64Ty,/*size*/
Int32Ty,/*tag*/
NULL);
trackUnInitInst = M.getOrInsertFunction("trackUnInitInst",
VoidTy,
VoidPtrTy,/*ptr*/
Int64Ty,/*size*/
Int32Ty,/*tag*/
NULL);
trackStoreInst = M.getOrInsertFunction("trackStoreInst",
VoidTy,
VoidPtrTy,/*ptr*/
TypeTagTy,/*type*/
Int64Ty,/*size*/
Int32Ty,/*tag*/
NULL);
getTypeTag = M.getOrInsertFunction("getTypeTag",
VoidTy,
VoidPtrTy, /*ptr*/
Int64Ty, /*size*/
TypeTagPtrTy, /*dest for type tag*/
Int32Ty, /*tag*/
NULL);
checkTypeInst = M.getOrInsertFunction("checkType",
VoidTy,
TypeTagTy,/*type*/
Int64Ty,/*size*/
TypeTagPtrTy,/*ptr to metadata*/
VoidPtrTy,/*ptr*/
Int32Ty,/*tag*/
NULL);
setTypeInfo = M.getOrInsertFunction("setTypeInfo",
VoidTy,
VoidPtrTy,/*dest ptr*/
TypeTagPtrTy,/*metadata*/
Int64Ty,/*size*/
TypeTagTy,
VoidPtrTy, /*src ptr*/
Int32Ty,/*tag*/
NULL);
copyTypeInfo = M.getOrInsertFunction("copyTypeInfo",
VoidTy,
VoidPtrTy,/*dest ptr*/
VoidPtrTy,/*src ptr*/
Int64Ty,/*size*/
Int32Ty,/*tag*/
NULL);
trackStringInput = M.getOrInsertFunction("trackStringInput",
VoidTy,
VoidPtrTy,
Int32Ty,
NULL);
setVAInfo = M.getOrInsertFunction("setVAInfo",
VoidTy,
VoidPtrTy,/*va_list ptr*/
Int64Ty,/*total num of elements in va_list */
TypeTagPtrTy,/*ptr to metadta*/
Int32Ty,/*tag*/
NULL);
copyVAInfo = M.getOrInsertFunction("copyVAInfo",
VoidTy,
VoidPtrTy,/*dst va_list*/
VoidPtrTy,/*src va_list */
Int32Ty,/*tag*/
NULL);
checkVAArg = M.getOrInsertFunction("checkVAArgType",
VoidTy,
VoidPtrTy,/*va_list ptr*/
TypeTagTy,/*type*/
Int32Ty,/*tag*/
NULL);
}
// Delete checks, if it is dominated by another check for the same value.
// We might get multiple checks on a path, if there are multiple uses of
// a load inst.
void TypeChecks::optimizeChecks(Module &M) {
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
Function &F = *MI;
if(F.isDeclaration())
continue;
DominatorTree & DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
std::deque<DomTreeNode *> Worklist;
Worklist.push_back (DT.getRootNode());
while(Worklist.size()) {
DomTreeNode * Node = Worklist.front();
Worklist.pop_front();
BasicBlock *BB = Node->getBlock();
for (BasicBlock::iterator bi = BB->begin(); bi != BB->end(); ++bi) {
CallInst *CI = dyn_cast<CallInst>(bi);
if(!CI)
continue;
if(CI->getCalledFunction() != checkTypeInst)
continue;
std::list<Instruction *>toDelete;
for(Value::user_iterator User = CI->getOperand(3)->user_begin(); User != CI->getOperand(3)->user_end(); ++User) {
CallInst *CI2 = dyn_cast<CallInst>(*User);
if(!CI2)
continue;
if(CI2 == CI)
continue;
// Check that they are refering to the same pointer
if(CI->getOperand(4) != CI2->getOperand(4))
continue;
// Check that they are using the same metadata for comparison.
if(CI->getOperand(3) != CI2->getOperand(3))
continue;
if(!DT.dominates(CI, CI2))
continue;
// if CI, dominates CI2, delete CI2
toDelete.push_back(CI2);
}
while(!toDelete.empty()) {
Instruction *I = toDelete.back();
toDelete.pop_back();
I->eraseFromParent();
}
}
Worklist.insert(Worklist.end(), Node->begin(), Node->end());
}
}
for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
Function &F = *MI;
if(F.isDeclaration())
continue;
DominatorTree & DT = getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
LoopInfo & LI = getAnalysis<LoopInfo>(F);
std::deque<DomTreeNode *> Worklist;
Worklist.push_back (DT.getRootNode());
while(Worklist.size()) {
DomTreeNode * Node = Worklist.front();
Worklist.pop_front();
Worklist.insert(Worklist.end(), Node->begin(), Node->end());
BasicBlock *BB = Node->getBlock();
Loop *L = LI.getLoopFor(BB);
if(!L)
continue;
if(!L->getLoopPreheader())
continue;
for (BasicBlock::iterator bi = BB->begin(); bi != BB->end(); ) {
CallInst *CI = dyn_cast<CallInst>(bi++);
if(!CI)
continue;
if(CI->getCalledFunction() != checkTypeInst)
continue;
bool hoist = true;
// The instruction is loop invariant if all of its operands are loop-invariant
for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i)
if (!L->isLoopInvariant(CI->getOperand(i)))
hoist = false;
if(hoist) {
CI->removeFromParent();
L->getLoopPreheader()->getInstList().insert(L->getLoopPreheader()->getTerminator(), CI);
}
}
}
}
}
// add a global that has the metadata -> typeString mapping
void TypeChecks::addTypeMap(Module &M) {
// Declare the type of the global
ArrayType* AType = ArrayType::get(VoidPtrTy, UsedTypes.size() + 1);
std::vector<Constant *> Values;
Values.reserve(UsedTypes.size() + 1);
// Declare indices useful for creating a GEP
std::vector<Constant *> Indices;
Indices.push_back(ConstantInt::get(Int32Ty,0));
Indices.push_back(ConstantInt::get(Int32Ty,0));
// Add an entry for uninitialized(Type Number = 0)
Constant *CA = ConstantDataArray::getString(M.getContext(),
"UNINIT", true);
GlobalVariable *GV = new GlobalVariable(M,
CA->getType(),
true,
GlobalValue::ExternalLinkage,
CA,
"");
GV->setInitializer(CA);
Constant *C = ConstantExpr::getGetElementPtr(GV,Indices);
Values[0] = C;
// For each used type, create a new entry.
// Also add these strings to the Values list
std::map<Type*, unsigned int >::iterator TI = UsedTypes.begin(),
TE = UsedTypes.end();
for(;TI!=TE; ++TI) {
std::string *type = new std::string();
llvm::raw_string_ostream *test = new llvm::raw_string_ostream(*type);
*test << TI->first;
//WriteTypeSymbolic(*test, TI->first, &M);
Constant *CA = ConstantDataArray::getString(M.getContext(),
test->str(), true);
GlobalVariable *GV = new GlobalVariable(M,
CA->getType(),
true,
GlobalValue::ExternalLinkage,
CA,
"");
GV->setInitializer(CA);
Constant *C = ConstantExpr::getGetElementPtr(GV, Indices);
Values[TI->second]= C;
}
new GlobalVariable(M,
AType,
true,
GlobalValue::ExternalLinkage,
ConstantArray::get(AType,Values),
"typeNames"
);
}
// For each address taken function, create a clone
// that takes 2 extra arguments(same as a var arg function).
// Modify call sites.
bool TypeChecks::visitAddressTakenFunction(Module &M, Function &F) {
// Clone function
// 1. Create the new argument types vector
std::vector<Type*> TP;
TP.push_back(Int64Ty); // for count
TP.push_back(VoidPtrTy); // for MD
for(Function::arg_iterator I = F.arg_begin(); I !=F.arg_end(); ++I) {
TP.push_back(I->getType());
}
// 2. Create the new function prototype
FunctionType *NewFTy = FunctionType::get(F.getReturnType(),
TP,
false);
Function *NewF = Function::Create(NewFTy,
GlobalValue::InternalLinkage,
F.getName().str() + ".mod",
&M);
// 3. Set the mapping for the args
Function::arg_iterator NI = NewF->arg_begin();
ValueToValueMapTy ValueMap;
NI->setName("TotalCount");
NI++;
NI->setName("MD");
NI++;
for(Function::arg_iterator II = F.arg_begin();
NI!=NewF->arg_end(); ++II, ++NI) {
// Each new argument maps to the argument in the old function
// For each of these also copy attributes
ValueMap[II] = NI;
NI->setName(II->getName());
NI->addAttr(F.getAttributes().getParamAttributes(II->getArgNo()+1));
}
// 4. Copy over attributes for the function
NewF->setAttributes(NewF->getAttributes()
.addAttributes(M.getContext(), 0, F.getAttributes().getRetAttributes()));
NewF->setAttributes(NewF->getAttributes()
.addAttributes(M.getContext(), ~0, F.getAttributes().getFnAttributes()));
// 5. Perform the cloning
SmallVector<ReturnInst*, 100>Returns;
// TODO: Review the boolean flag here
CloneFunctionInto(NewF, &F, ValueMap, true, Returns);
// Store in the map of original -> cloned function
IndFunctionsMap[&F] = NewF;
std::vector<Instruction *>toDelete;
// Find all uses of the function
for(Value::user_iterator ui = F.user_begin(), ue = F.user_end();
ui != ue;++ui) {
if(InvokeInst *II = dyn_cast<InvokeInst>(*ui)) {
if(II->getCalledValue()->stripPointerCasts() != &F)
continue;
std::vector<Value *> Args;
inst_iterator InsPt = inst_begin(II->getParent()->getParent());
unsigned int i;
unsigned int NumArgs = II->getNumOperands() - 3;
Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs);
AllocaInst *AI = new AllocaInst(TypeTagTy, NumArgsVal, "", &*InsPt);
// set the metadata for the varargs in AI
for(i = 3; i <II->getNumOperands(); i++) {
Value *Idx[1];
Idx[0] = ConstantInt::get(Int32Ty, i - 3 );
// For each vararg argument, also add its type information
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI,Idx, "", II);
Constant *C = getTypeMarkerConstant(II->getOperand(i));
new StoreInst(C, GEP, II);
}
// As the first argument pass the number of var_arg arguments
Args.push_back(ConstantInt::get(Int64Ty, NumArgs));
Args.push_back(AI);
for(i = 3 ;i < II->getNumOperands(); i++) {
// Add the original argument
Args.push_back(II->getOperand(i));
}
// Create the new call
InvokeInst *II_New = InvokeInst::Create(NewF,
II->getNormalDest(),
II->getUnwindDest(),
Args,
"", II);
II->replaceAllUsesWith(II_New);
toDelete.push_back(II);
}
// Check for call sites
else if(CallInst *CI = dyn_cast<CallInst>(*ui)) {
if(CI->getCalledValue()->stripPointerCasts() != &F)
continue;
std::vector<Value *> Args;
unsigned int i;
unsigned int NumArgs = CI->getNumOperands() - 1;
inst_iterator InsPt = inst_begin(CI->getParent()->getParent());
Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs);
AllocaInst *AI = new AllocaInst(TypeTagTy, NumArgsVal, "", &*InsPt);
// set the metadata for the varargs in AI
for(i = 1; i <CI->getNumOperands(); i++) {
Value *Idx[1];
Idx[0] = ConstantInt::get(Int32Ty, i - 1 );
// For each vararg argument, also add its type information
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI,Idx, "", CI);
Constant *C = getTypeMarkerConstant(CI->getOperand(i));
new StoreInst(C, GEP, CI);
}
// As the first argument pass the number of var_arg arguments
Args.push_back(ConstantInt::get(Int64Ty, NumArgs));
Args.push_back(AI);
for(i = 1 ;i < CI->getNumOperands(); i++) {
// Add the original argument
Args.push_back(CI->getOperand(i));
}
// Create the new call
CallInst *CI_New = CallInst::Create(NewF, Args, "", CI);
CI->replaceAllUsesWith(CI_New);
toDelete.push_back(CI);
}
}
while(!toDelete.empty()) {
Instruction *I = toDelete.back();
toDelete.pop_back();
I->eraseFromParent();
}
return true;
}
// Transform Variable Argument functions, by also passing
// the relavant metadata info
bool TypeChecks::visitVarArgFunction(Module &M, Function &F) {
if(F.hasInternalLinkage()) {
return visitInternalVarArgFunction(M, F);
}
// create internal clone
ValueToValueMapTy VMap;
Function *F_clone = CloneFunction(&F, VMap, false);
F_clone->setName(F.getName().str() + "internal");
F.setLinkage(GlobalValue::InternalLinkage);
F.getParent()->getFunctionList().push_back(F_clone);
F.replaceAllUsesWith(F_clone);
return visitInternalVarArgFunction(M, *F_clone);
}
// each vararg function is modified so that the first
// argument is the number of arguments passed in,
// and the second is a pointer to a metadata array,
// containing type information for each of the arguments
// These are read and stored at the beginning of the function.
// We keep a counter for the number of arguments accessed
// from the va_list(Counter). It is incremented and
// checked on every va_arg access. It is initialized to zero.
// It is also reset to zero on a call to va_start.
// Similiarly we check type on every va_arg access.
// Aside from this, this function also transforms all
// callsites of the var_arg function.
bool TypeChecks::visitInternalVarArgFunction(Module &M, Function &F) {
// Clone function
// 1. Create the new argument types vector
std::vector<Type*> TP;
TP.push_back(Int64Ty); // for count
TP.push_back(TypeTagPtrTy); // for MD
for(Function::arg_iterator I = F.arg_begin(); I !=F.arg_end(); ++I) {
TP.push_back(I->getType());
}
// 2. Create the new function prototype
FunctionType *NewFTy = FunctionType::get(F.getReturnType(),
TP,
true);
Function *NewF = Function::Create(NewFTy,
GlobalValue::InternalLinkage,
F.getName().str() + ".vararg",
&M);
// 3. Set the mapping for the args
Function::arg_iterator NI = NewF->arg_begin();
ValueToValueMapTy ValueMap;
NI->setName("TotalArgCount");
NI++;
NI->setName("MD");
NI++;
for(Function::arg_iterator II = F.arg_begin();
NI!=NewF->arg_end(); ++II, ++NI) {
// Each new argument maps to the argument in the old function
// For each of these also copy attributes
ValueMap[II] = NI;
NI->setName(II->getName());
NI->addAttr(F.getAttributes().getParamAttributes(II->getArgNo()+1));
}
// 4. Copy over attributes for the function
NewF->setAttributes(NewF->getAttributes()
.addAttributes(M.getContext(), 0, F.getAttributes().getRetAttributes()));
NewF->setAttributes(NewF->getAttributes()
.addAttributes(M.getContext(), ~0, F.getAttributes().getFnAttributes()));
// 5. Perform the cloning
SmallVector<ReturnInst*, 100>Returns;
// TODO: Review the boolean flag here
CloneFunctionInto(NewF, &F, ValueMap, true, Returns);
// Store the information
inst_iterator InsPt = inst_begin(NewF);
Function::arg_iterator NII = NewF->arg_begin();
// Subtract the number of initial arguments
Constant *InitialArgs = ConstantInt::get(Int64Ty, F.arg_size());
Instruction *NewValue = BinaryOperator::Create(BinaryOperator::Sub,
NII,
InitialArgs,
"varargs",
&*InsPt);
NII++;
// Increment by the number of Initial Args, so as to not read the metadata
//for those.
Value *Idx[1];
Idx[0] = InitialArgs;
// For each vararg argument, also add its type information
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(NII,Idx, "", &*InsPt);
// visit all VAStarts and initialize the counter
for (Function::iterator B = NewF->begin(), FE = NewF->end(); B != FE; ++B) {
for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;I++) {
CallInst *CI = dyn_cast<CallInst>(I);
if(!CI)
continue;
Function *CalledF = dyn_cast<Function>(CI->getCalledFunction());
if(!CalledF)
continue;
if(!CalledF->isIntrinsic())
continue;
if(CalledF->getIntrinsicID() != Intrinsic::vastart)
continue;
// Reinitialize the counter
Value *BCI = castTo(CI->getArgOperand(0), VoidPtrTy, "", CI);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(NewValue);
Args.push_back(GEP);
Args.push_back(getTagCounter());
CallInst::Create(setVAInfo, Args, "", CI);
}
}
// Find all va_copy calls
for (Function::iterator B = NewF->begin(), FE = NewF->end(); B != FE; ++B) {
for (BasicBlock::iterator I = B->begin(), BE = B->end(); I != BE;I++) {
CallInst *CI = dyn_cast<CallInst>(I);
if(!CI)
continue;
Function *CalledF = dyn_cast<Function>(CI->getCalledFunction());
if(!CalledF)
continue;
if(!CalledF->isIntrinsic())
continue;
if(CalledF->getIntrinsicID() != Intrinsic::vacopy)
continue;
Value *BCI_Src = castTo(CI->getArgOperand(1), VoidPtrTy, "", CI);
Value *BCI_Dest = castTo(CI->getArgOperand(0), VoidPtrTy, "", CI);
std::vector<Value *> Args;
Args.push_back(BCI_Dest);
Args.push_back(BCI_Src);
Args.push_back(getTagCounter());
CallInst::Create(copyVAInfo, Args, "", CI);
}
}
std::vector<Instruction *>toDelete;
// Find all uses of the function
for(Value::user_iterator ui = F.user_begin(), ue = F.user_end();
ui != ue;ui ++) {
// Check for call sites
if(InvokeInst *II = dyn_cast<InvokeInst>(*ui)) {
std::vector<Value *> Args;
inst_iterator InsPt = inst_begin(II->getParent()->getParent());
unsigned int i;
unsigned int NumArgs = II->getNumOperands() - 3;
Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs);
AllocaInst *AI = new AllocaInst(TypeTagTy, NumArgsVal, "", &*InsPt);
// set the metadata for the varargs in AI
for(i = 3; i <II->getNumOperands(); i++) {
Value *Idx[1];
Idx[0] = ConstantInt::get(Int32Ty, i - 3 );
// For each vararg argument, also add its type information
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI, Idx, "", II);
Constant *C = getTypeMarkerConstant(II->getOperand(i));
new StoreInst(C, GEP, II);
}
// As the first argument pass the number of var_arg arguments
Args.push_back(ConstantInt::get(Int64Ty, NumArgs));
Args.push_back(AI);
for(i = 3 ;i < II->getNumOperands(); i++) {
// Add the original argument
Args.push_back(II->getOperand(i));
}
// Create the new call
InvokeInst *II_New = InvokeInst::Create(NewF,
II->getNormalDest(),
II->getUnwindDest(),
Args,
"", II);
II->replaceAllUsesWith(II_New);
toDelete.push_back(II);
} else if (CallInst *CI = dyn_cast<CallInst>(*ui)) {
std::vector<Value *> Args;
inst_iterator InsPt = inst_begin(CI->getParent()->getParent());
unsigned int i;
unsigned int NumArgs = CI->getNumArgOperands();
Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs);
AllocaInst *AI = new AllocaInst(TypeTagTy, NumArgsVal, "", &*InsPt);
// set the metadata for the varargs in AI
for(i = 0; i <CI->getNumArgOperands(); i++) {
Value *Idx[1];
Idx[0] = ConstantInt::get(Int32Ty, i);
// For each vararg argument, also add its type information
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI,Idx, "", CI);
Constant *C = getTypeMarkerConstant(CI->getArgOperand(i));
new StoreInst(C, GEP, CI);
}
// As the first argument pass the number of var_arg arguments
Args.push_back(ConstantInt::get(Int64Ty, NumArgs));
Args.push_back(AI);
for(i = 0 ;i < CI->getNumArgOperands(); i++) {
// Add the original argument
Args.push_back(CI->getArgOperand(i));
}
// Create the new call
CallInst *CI_New = CallInst::Create(NewF, Args, "", CI);
CI->replaceAllUsesWith(CI_New);
toDelete.push_back(CI);
}
}
while(!toDelete.empty()) {
Instruction *I = toDelete.back();
toDelete.pop_back();
I->eraseFromParent();
}
IndFunctionsMap[&F] = NewF;
return true;
}
bool TypeChecks::visitByValFunction(Module &M, Function &F) {
// For internal functions
// Replace with a function with a a new function with no byval attr.
// Add an explicity copy in the function
// Also update all the call sites.
// For external functions
// Create an internal clone (treated same as internal functions)
// Modify the original function
// To assume that the metadata for the byval arguments is TOP
if(F.hasInternalLinkage()) {
visitInternalByValFunction(M, F);
} else {
// create internal clone
ValueToValueMapTy VMap;
Function *F_clone = CloneFunction(&F, VMap, false);
F_clone->setName(F.getName().str() + "internal");
F.setLinkage(GlobalValue::InternalLinkage);
F.getParent()->getFunctionList().push_back(F_clone);
F.replaceAllUsesWith(F_clone);
visitInternalByValFunction(M, *F_clone);
visitExternalByValFunction(M, F);
}
return true;
}
bool TypeChecks::visitInternalByValFunction(Module &M, Function &F) {
// for every byval argument
// add an alloca, a load, and a store inst
Instruction * InsertBefore = &(F.getEntryBlock().front());
for (Function::arg_iterator I = F.arg_begin(); I != F.arg_end(); ++I) {
if (!I->hasByValAttr())
continue;
assert(I->getType()->isPointerTy());
Type *ETy = (cast<PointerType>(I->getType()))->getElementType();
AllocaInst *AI = new AllocaInst(ETy, "", InsertBefore);
// Do this before adding the load/store pair, so that those uses are not replaced.
I->replaceAllUsesWith(AI);
LoadInst *LI = new LoadInst(I, "", InsertBefore);
new StoreInst(LI, AI, InsertBefore);
}
// Update the call sites
std::vector<Instruction *>toDelete;
for(Value::user_iterator ui = F.user_begin(), ue = F.user_end();
ui != ue; ui++) {
// Check that F is the called value
if(InvokeInst *II = dyn_cast<InvokeInst>(*ui)) {
if(II->getCalledFunction() == &F) {
SmallVector<Value*, 8> Args;
// TODO: not a good idea:
AttributeSet NewCallPAL=AttributeSet();
// Get the initial attributes of the call
AttributeSet CallPAL = II->getAttributes();
AttributeSet RAttrs = CallPAL.getRetAttributes();
AttributeSet FnAttrs = CallPAL.getFnAttributes();
if (!RAttrs.isEmpty())
NewCallPAL=NewCallPAL.addAttributes(F.getContext() ,0, RAttrs);
Function::arg_iterator NI = F.arg_begin();
for(unsigned j =3;j<II->getNumOperands();j++, NI++) {
// Add the original argument
Args.push_back(II->getOperand(j));
// If there are attributes on this argument, copy them to the correct
// position in the NewCallPAL
//FIXME: copy the rest of the attributes.
if(NI->hasByValAttr())
continue;
AttributeSet Attrs = CallPAL.getParamAttributes(j);
if (!Attrs.isEmpty()) {
NewCallPAL=NewCallPAL.addAttributes(F.getContext(), j, Attrs);
}
}
// Create the new attributes vec.
if (!FnAttrs.isEmpty())
NewCallPAL=NewCallPAL.addAttributes(F.getContext(),~0, FnAttrs);
// Create the substitute call
InvokeInst *CallI = InvokeInst::Create(&F,
II->getNormalDest(),
II->getUnwindDest(),
Args,
"", II);
CallI->setCallingConv(II->getCallingConv());
CallI->setAttributes(NewCallPAL);
II->replaceAllUsesWith(CallI);
toDelete.push_back(II);
}
} else if(CallInst *CI = dyn_cast<CallInst>(*ui)) {
if(CI->getCalledFunction() == &F) {
SmallVector<Value*, 8> Args;
// TODO: not a good idea:
AttributeSet NewCallPAL=AttributeSet();
// Get the initial attributes of the call
AttributeSet CallPAL = CI->getAttributes();
AttributeSet RAttrs = CallPAL.getRetAttributes();
AttributeSet FnAttrs = CallPAL.getFnAttributes();
if (!RAttrs.isEmpty())
NewCallPAL=NewCallPAL.addAttributes(F.getContext(),0, RAttrs);
Function::arg_iterator II = F.arg_begin();
for(unsigned j =1;j<CI->getNumOperands();j++, II++) {
// Add the original argument
Args.push_back(CI->getOperand(j));
// If there are attributes on this argument, copy them to the correct
// position in the NewCallPAL
//FIXME: copy the rest of the attributes.
if(II->hasByValAttr())
continue;
AttributeSet Attrs = CallPAL.getParamAttributes(j);
if (!Attrs.isEmpty()) {
NewCallPAL=NewCallPAL.addAttributes(F.getContext(),j, Attrs);
}
}
// Create the new attributes vec.
if (!FnAttrs.isEmpty())
NewCallPAL=NewCallPAL.addAttributes(F.getContext(),~0, FnAttrs);
// Create the substitute call
CallInst *CallI = CallInst::Create(&F,
Args,
"", CI);
CallI->setCallingConv(CI->getCallingConv());
CallI->setAttributes(NewCallPAL);
CI->replaceAllUsesWith(CallI);
toDelete.push_back(CI);
}
}
}
while(!toDelete.empty()) {
Instruction *I = toDelete.back();
toDelete.pop_back();
I->eraseFromParent();
}
// remove the byval attribute from the function
AttrBuilder B;
B.addAttribute(Attribute::ByVal);
for (Function::arg_iterator I = F.arg_begin(); I != F.arg_end(); ++I) {
if (!I->hasByValAttr())
continue;
I->removeAttr(AttributeSet::get(M.getContext(),0, B));
}
return true;
}
bool TypeChecks::visitExternalByValFunction(Module &M, Function &F) {
// A list of the byval arguments that we are setting metadata for
typedef SmallVector<Value *, 4> RegisteredArgTy;
RegisteredArgTy registeredArguments;
for (Function::arg_iterator I = F.arg_begin(); I != F.arg_end(); ++I) {
if (I->hasByValAttr()) {
assert (isa<PointerType>(I->getType()));
PointerType * PT = cast<PointerType>(I->getType());
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
Instruction * InsertPt = &(F.getEntryBlock().front());
Value *BCI = castTo(I, VoidPtrTy, "", InsertPt);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(AllocSize);
Args.push_back(getTagCounter());
// Set the metadata for the byval argument to TOP/Initialized
CallInst::Create(trackInitInst, Args, "", InsertPt);
registeredArguments.push_back(&*I);
}
}
// Find all basic blocks which terminate the function.
std::set<BasicBlock *> exitBlocks;
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) {
if (isa<ReturnInst>(*I) || isa<ResumeInst>(*I)) {
exitBlocks.insert(I->getParent());
}
}
// At each function exit, insert code to set the metadata as uninitialized.
for (std::set<BasicBlock*>::const_iterator BI = exitBlocks.begin(),
BE = exitBlocks.end();
BI != BE; ++BI) {
for (RegisteredArgTy::const_iterator I = registeredArguments.begin(),
E = registeredArguments.end();
I != E; ++I) {
SmallVector<Value *, 2> args;
Instruction * Pt = &((*BI)->back());
PointerType * PT = cast<PointerType>((*I)->getType());
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
Value *BCI = castTo(*I, VoidPtrTy, "", Pt);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(AllocSize);
Args.push_back(getTagCounter());
CallInst::Create(trackUnInitInst, Args, "", Pt);
}
}
return true;
}
// Print the types found in the module. If the optional Module parameter is
// passed in, then the types are printed symbolically if possible, using the
// symbol table from the module.
void TypeChecks::print(raw_ostream &OS, const Module *M) const {
OS << "Types in use by this module:\n";
std::map<Type *,unsigned int>::const_iterator I = UsedTypes.begin(),
E = UsedTypes.end();
for (; I != E; ++I) {
OS << " ";
OS << I->first;
// WriteTypeSymbolic(OS, I->first, M);
OS << " : " << I->second;
OS << '\n';
}
OS << "\nNumber of types: " << UsedTypes.size() << '\n';
}
// Initialize the shadow memory which contains the 1:1 mapping.
bool TypeChecks::initShadow(Module &M) {
// Create the call to the runtime initialization function and place it before the store instruction.
Constant * RuntimeCtor = M.getOrInsertFunction("tc.init", VoidTy, NULL);
Constant * InitFn = M.getOrInsertFunction("shadowInit", VoidTy, NULL);
//RuntimeCtor->setDoesNotThrow();
//RuntimeCtor->setLinkage(GlobalValue::InternalLinkage);
BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", cast<Function>(RuntimeCtor));
CallInst::Create(InitFn, "", BB);
Instruction *InsertPt = ReturnInst::Create(M.getContext(), BB);
// record all globals
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I) {
if(I->use_empty())
continue;
if(I->getName().str() == "stderr" ||
I->getName().str() == "stdout" ||
I->getName().str() == "stdin" ||
I->getName().str() == "optind" ||
I->getName().str() == "optarg") {
// assume initialized
Value *BCI = castTo(I, VoidPtrTy, "", InsertPt);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(I->getType()->getElementType()));
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", InsertPt);
continue;
}
if(!I->hasInitializer())
continue;
SmallVector<Value*,8>index;
index.push_back(Zero);
visitGlobal(M, *I, I->getInitializer(), *InsertPt, index);
}
//
// Insert the run-time ctor into the ctor list.
//
std::vector<Constant *> CtorInits;
CtorInits.push_back (ConstantInt::get (Int32Ty, 65535));
CtorInits.push_back (RuntimeCtor);
Constant * RuntimeCtorInit=ConstantStruct::getAnon(M.getContext(),CtorInits, false);
//
// Get the current set of static global constructors and add the new ctor
// to the list.
//
std::vector<Constant *> CurrentCtors;
GlobalVariable * GVCtor = M.getNamedGlobal ("llvm.global_ctors");
if (GVCtor) {
if (Constant * C = GVCtor->getInitializer()) {
for (unsigned index = 0; index < C->getNumOperands(); ++index) {
CurrentCtors.push_back (cast<Constant>(C->getOperand (index)));
}
}
//
// Rename the global variable so that we can name our global
// llvm.global_ctors.
//
GVCtor->setName ("removed");
}
//
// The ctor list seems to be initialized in different orders on different
// platforms, and the priority settings don't seem to work. Examine the
// module's platform string and take a best guess to the order.
//
if (M.getTargetTriple().find ("linux") == std::string::npos)
CurrentCtors.insert (CurrentCtors.begin(), RuntimeCtorInit);
else
CurrentCtors.push_back (RuntimeCtorInit);
//
// Create a new initializer.
//
ArrayType * AT = ArrayType::get (RuntimeCtorInit-> getType(),
CurrentCtors.size());
Constant * NewInit=ConstantArray::get (AT, CurrentCtors);
//
// Create the new llvm.global_ctors global variable and replace all uses of
// the old global variable with the new one.
//
new GlobalVariable (M,
NewInit->getType(),
false,
GlobalValue::AppendingLinkage,
NewInit,
"llvm.global_ctors");
return true;
}
bool TypeChecks::visitMain(Module &M, Function &MainFunc) {
if(MainFunc.arg_size() < 2)
// No need to register
return false;
Function::arg_iterator AI = MainFunc.arg_begin();
Value *Argc = AI;
Value *Argv = ++AI;
Instruction *InsertPt = MainFunc.front().begin();
std::vector<Value *> fargs;
fargs.push_back (Argc);
fargs.push_back (Argv);
CallInst::Create (RegisterArgv, fargs, "", InsertPt);
if(MainFunc.arg_size() < 3)
return true;
Value *Envp = ++AI;
std::vector<Value*> Args;
Args.push_back(Envp);
CallInst::Create(RegisterEnvp, Args, "", InsertPt);
return true;
}
bool TypeChecks::visitGlobal(Module &M, GlobalVariable &GV,
Constant *C, Instruction &I, SmallVector<Value *,8> Indices) {
if(ConstantArray *CA = dyn_cast<ConstantArray>(C)) {
Type * ElementType = CA->getType()->getElementType();
// Create the type entry for the first element
// using recursive creation till we get to the base types
Indices.push_back(ConstantInt::get(Int64Ty,0));
visitGlobal(M, GV, CA->getOperand(0), I, Indices);
Indices.pop_back();
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I);
Value *BCI = castTo(GEP, VoidPtrTy, "", &I);
// Copy the type metadata for the first element
// over for the rest of the elements.
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(ElementType));
Args.push_back(ConstantInt::get(Int64Ty, CA->getNumOperands()));
Args.push_back(getTagCounter());
CallInst::Create(trackArray, Args, "", &I);
}
else if(ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) {
// Create metadata for each field of the struct
// at the correct offset.
const StructLayout *SL = TD->getStructLayout(cast<StructType>(CS->getType()));
for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) {
if (SL->getElementOffset(i) < SL->getSizeInBytes()) {
Constant * ConstElement = cast<Constant>(CS->getOperand(i));
Indices.push_back(ConstantInt::get(Int32Ty, i));
visitGlobal(M, GV, ConstElement, I, Indices);
Indices.pop_back();
}
}
} else if(ConstantAggregateZero *CAZ = dyn_cast<ConstantAggregateZero>(C)) {
// Similiar to having an initializer with all values NULL
// Must set metadata, similiar to the previous 2 cases.
Type *Ty = CAZ->getType();
if(ArrayType * ATy = dyn_cast<ArrayType>(Ty)) {
Type * ElementType = ATy->getElementType();
Indices.push_back(ConstantInt::get(Int64Ty,0));
visitGlobal(M, GV, Constant::getNullValue(ElementType), I, Indices);
Indices.pop_back();
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I);
Value *BCI = castTo(GEP, VoidPtrTy, "", &I);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(ElementType));
Args.push_back(ConstantInt::get(Int64Ty, ATy->getNumElements()));
Args.push_back(getTagCounter());
CallInst::Create(trackArray, Args, "", &I);
} else if(StructType *STy = dyn_cast<StructType>(Ty)) {
const StructLayout *SL = TD->getStructLayout(STy);
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
if (SL->getElementOffset(i) < SL->getSizeInBytes()) {
Indices.push_back(ConstantInt::get(Int32Ty, i));
visitGlobal(M, GV, Constant::getNullValue(STy->getElementType(i)), I, Indices);
Indices.pop_back();
}
}
} else {
// Zeroinitializer of a primitive type
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I);
Value *BCI = castTo(GEP, VoidPtrTy, "", &I);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getTypeMarkerConstant(CAZ));
Args.push_back(getSizeConstant(CAZ->getType()));
Args.push_back(getTagCounter());
CallInst::Create(trackGlobal, Args, "", &I);
}
}
else {
// Primitive type value
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(&GV, Indices, "", &I);
Value *BCI = castTo(GEP, VoidPtrTy, "", &I);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getTypeMarkerConstant(C));
Args.push_back(getSizeConstant(C->getType()));
Args.push_back(getTagCounter());
CallInst::Create(trackGlobal, Args, "", &I);
}
return true;
}
bool TypeChecks::visitVAArgInst(Module &M, VAArgInst &VI) {
if(!VI.getParent()->getParent()->hasInternalLinkage())
return false;
Value *BCI = castTo(VI.getOperand(0), VoidPtrTy, "", &VI);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTypeMarkerConstant(&VI));
Args.push_back(getTagCounter());
CallInst::Create(checkVAArg, Args, "", &VI);
return false;
}
// Insert code to initialize meta data to bottom
// Insert code to set objects to 0
bool TypeChecks::visitAllocaInst(Module &M, AllocaInst &AI) {
PointerType * PT = AI.getType();
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
CastInst *BCI = BitCastInst::CreatePointerCast(&AI, VoidPtrTy);
BCI->insertAfter(&AI);
Value *TotalSize;
if(!AI.isArrayAllocation()) {
TotalSize = AllocSize;
} else {
CastInst *ArraySize = CastInst::CreateSExtOrBitCast(AI.getArraySize(), Int64Ty, "", &AI);
BinaryOperator *Size = BinaryOperator::Create(Instruction::Mul, AllocSize, ArraySize, "", &AI);
TotalSize = Size;
}
// Setting metadata to be 0(BOTTOM/Uninitialized)
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(TotalSize);
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackUnInitInst, Args);
CI->insertAfter(BCI);
return true;
}
// Insert runtime checks for certain call instructions
bool TypeChecks::visitCallInst(Module &M, CallInst &CI) {
return visitCallSite(M, &CI);
}
// Insert runtime checks for certain call instructions
bool TypeChecks::visitInvokeInst(Module &M, InvokeInst &II) {
return visitCallSite(M, &II);
}
bool TypeChecks::visitCallSite(Module &M, CallSite CS) {
//
// Get the called value. Strip off any casts which are lossless.
//
Value *Callee = CS.getCalledValue()->stripPointerCasts();
Instruction *I = CS.getInstruction();
// Special case handling of certain libc allocation functions here.
if (Function *F = dyn_cast<Function>(Callee)) {
if (F->isIntrinsic()) {
switch(F->getIntrinsicID()) {
case Intrinsic::memcpy:
case Intrinsic::memmove:
{
Value *BCI_Src = castTo(CS.getArgument(1), VoidPtrTy, "", I);
Value *BCI_Dest = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value *> Args;
Args.push_back(BCI_Dest);
Args.push_back(BCI_Src);
CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(2), Int64Ty, false, "", I);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst::Create(copyTypeInfo, Args, "", I);
return true;
}
case Intrinsic::memset:
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value *> Args;
Args.push_back(BCI);
CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(2), Int64Ty, false, "", I);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
return true;
}
} else if (F->getName().str() == std::string("_ZNKSs5c_strEv")) { //c_str
std::vector<Value *>Args;
Args.push_back(I);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
Instruction *InsertPt = I;
if (InvokeInst *II = dyn_cast<InvokeInst>(InsertPt)) {
InsertPt = II->getNormalDest()->begin();
while (isa<PHINode>(InsertPt))
++InsertPt;
} else
++InsertPt;
CI->insertBefore(InsertPt);
} else if (F->getName().str() == std::string("_ZNSsC1EPKcRKSaIcE")) { //c_str()
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
Instruction *InsertPt = I;
if (InvokeInst *II = dyn_cast<InvokeInst>(InsertPt)) {
InsertPt = II->getNormalDest()->begin();
while (isa<PHINode>(InsertPt))
++InsertPt;
} else
++InsertPt;
CI->insertBefore(InsertPt);
} else if (F->getName().str() == std::string("accept")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(1), VoidPtrTy);
BCI->insertAfter(I);
CastInst *BCI_Size = BitCastInst::CreatePointerCast(CS.getArgument(2), VoidPtrTy);
BCI_Size->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(BCI_Size);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackaccept", VoidTy, VoidPtrTy,VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("poll")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value*>Args;
Args.push_back(BCI);
Args.push_back(CS.getArgument(1));
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackpoll", VoidTy, VoidPtrTy, Int64Ty, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("getaddrinfo")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(3), VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetaddrinfo", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("mmap")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(CS.getArgument(1));
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("__strdup")) {
CastInst *BCI_Dest = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI_Dest->insertAfter(I);
CastInst *BCI_Src = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy);
BCI_Src->insertAfter(BCI_Dest);
std::vector<Value *> Args;
Args.push_back(BCI_Dest);
Args.push_back(BCI_Src);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackStrcpyInst", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI_Src);
} else if (F->getName().str() == std::string("gettimeofday") ||
F->getName().str() == std::string("time") ||
F->getName().str() == std::string("times")) {
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
assert (isa<PointerType>(CS.getArgument(0)->getType()));
PointerType * PT = cast<PointerType>(CS.getArgument(0)->getType());
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(AllocSize);
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
} else if (F->getName().str() == std::string("getpwuid")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetpwuid", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("getpwnam")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetpwuid", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if(F->getName().str() == std::string("getopt_long")) {
Value *OptArg = M.getNamedGlobal("optarg");
LoadInst *LI = new LoadInst(OptArg);
LI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(LI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(LI);
} else if (F->getName().str() == std::string("getgruid") ||
F->getName().str() == std::string("getgrnam") ||
F->getName().str() == std::string("getpwnam") ||
F->getName().str() == std::string("__errno_location")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
assert (isa<PointerType>(I->getType()));
PointerType * PT = cast<PointerType>(I->getType());
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
BCI->insertAfter(I);
std::vector<Value*>Args;
Args.push_back(BCI);
Args.push_back(AllocSize);
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("getservbyname")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value*>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetservbyname", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("gethostbyname") ||
F->getName().str() == std::string("gethostbyaddr")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value*>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgethostbyname", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("gethostname")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value*>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgethostname", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("getenv") ||
F->getName().str() == std::string("strerror") ||
F->getName().str() == std::string("inet_ntoa")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("getcwd")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if(F->getName().str() == std::string("crypt")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("getrusage") ||
F->getName().str() == std::string("getrlimit") ||
F->getName().str() == std::string("stat") ||
F->getName().str() == std::string("vfsstat") ||
F->getName().str() == std::string("fstat") ||
F->getName().str() == std::string("lstat")) {
Value *BCI = castTo(CS.getArgument(1), VoidPtrTy, "", I);
assert (isa<PointerType>(CS.getArgument(1)->getType()));
PointerType * PT = cast<PointerType>(CS.getArgument(1)->getType());
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(AllocSize);
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
} else if (F->getName().str() == std::string("sigaction")) {
Value *BCI = castTo(CS.getArgument(2), VoidPtrTy, "", I);
assert (isa<PointerType>(CS.getArgument(2)->getType()));
PointerType * PT = cast<PointerType>(CS.getArgument(2)->getType());
Type * ET = PT->getElementType();
Value * AllocSize = ConstantInt::get(Int64Ty, TD->getTypeAllocSize(ET));
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(AllocSize);
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
} else if (F->getName().str() == std::string("__ctype_b_loc")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackctype", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("__ctype_toupper_loc")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackctype_32", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("__ctype_tolower_loc")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackctype_32", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("strtol") ||
F->getName().str() == std::string("strtod")) {
Value *BCI = castTo(CS.getArgument(1), VoidPtrTy, "", I);
PointerType *PTy = cast<PointerType>(CS.getArgument(1)->getType());
Type * ElementType = PTy->getElementType();
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(ElementType));
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
return true;
} else if (F->getName().str() == std::string("strcat") ||
F->getName().str() == std::string("_ZNSspLEPKc")) {
Value *BCI_Src = castTo(CS.getArgument(1), VoidPtrTy, "", I);
Value *BCI_Dest = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value *> Args;
Args.push_back(BCI_Dest);
Args.push_back(BCI_Src);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackStrcatInst", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty, NULL);
CallInst::Create(F, Args, "", I);
} else if (F->getName().str() == std::string("strcpy")) {
std::vector<Value *> Args;
Args.push_back(CS.getArgument(0));
Args.push_back(CS.getArgument(1));
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackStrcpyInst", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty, NULL);
CallInst::Create(F, Args, "", I);
} else if (F->getName().str() == std::string("strncpy")) {
std::vector<Value *>Args;
Args.push_back(CS.getArgument(0));
Args.push_back(CS.getArgument(1));
Args.push_back(CS.getArgument(2));
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackStrncpyInst", VoidTy, VoidPtrTy, VoidPtrTy, I->getOperand(3)->getType(), Int32Ty, NULL);
CallInst::Create(F, Args, "", I);
} else if (F->getName().str() == std::string("readlink")) {
std::vector<Value *>Args;
Args.push_back(CS.getArgument(1));
Args.push_back(I);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackReadLink", VoidTy, VoidPtrTy, I->getType(), Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(I);
} else if (F->getName().str() == std::string("pipe")) {
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value*> Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackpipe", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst::Create(F, Args, "", I);
return true;
} else if (F->getName().str() == std::string("getsockname")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(1), VoidPtrTy);
BCI->insertAfter(I);
CastInst *BCI_Size = BitCastInst::CreatePointerCast(CS.getArgument(2), VoidPtrTy);
BCI_Size->insertAfter(I);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(BCI_Size);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetsockname", VoidTy, VoidPtrTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CI = CallInst::Create(F, Args);
CI->insertAfter(BCI);
return true;
} else if (F->getName().str() == std::string("readdir")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
PointerType *PTy = cast<PointerType>(I->getType());
Type * ElementType = PTy->getElementType();
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(ElementType));
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
return true;
} else if (F->getName().str() == std::string("localtime") ||
F->getName().str() == std::string("gmtime")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
PointerType *PTy = cast<PointerType>(I->getType());
Type * ElementType = PTy->getElementType();
std::vector<Value *>Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(ElementType));
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
} else if (F->getName().str() == std::string("ftime") ||
F->getName().str() == std::string("gettimeofday")) {
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
PointerType *PTy = cast<PointerType>(CS.getArgument(0)->getType());
Type * ElementType = PTy->getElementType();
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getSizeConstant(ElementType));
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
return true;
} else if(F->getName().str() == std::string("read")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(1), VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *> Args;
Args.push_back(BCI);
CastInst *Size = CastInst::CreateIntegerCast(I, Int64Ty, false);
Size->insertAfter(I);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
return true;
} else if(F->getName().str() == std::string("fread")) {
CastInst *BCI = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *> Args;
Args.push_back(BCI);
CastInst *Elem = CastInst::CreateIntegerCast(I, Int64Ty, false);
BinaryOperator *Size = BinaryOperator::Create(Instruction::Mul, Elem, CS.getArgument(1));
Elem->insertAfter(I);
Size->insertAfter(Elem);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
return true;
} else if(F->getName().str() == std::string("calloc")) {
CastInst *BCI = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI->insertAfter(I);
std::vector<Value *> Args;
Args.push_back(BCI);
CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(1), Int64Ty, false, "", I);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(trackInitInst, Args);
CI->insertAfter(BCI);
std::vector<Value *> Args1;
Args1.push_back(BCI);
Args1.push_back(Size);
CastInst *Num = CastInst::CreateIntegerCast(CS.getArgument(0), Int64Ty, false, "", I);
Args1.push_back(Num);
Args1.push_back(getTagCounter());
CallInst *CI_Arr = CallInst::Create(trackArray, Args1);
CI_Arr->insertAfter(CI);
return true;
} else if(F->getName().str() == std::string("realloc")) {
CastInst *BCI_Src = BitCastInst::CreatePointerCast(CS.getArgument(0), VoidPtrTy);
CastInst *BCI_Dest = BitCastInst::CreatePointerCast(I, VoidPtrTy);
BCI_Src->insertAfter(I);
BCI_Dest->insertAfter(BCI_Src);
std::vector<Value *> Args;
Args.push_back(BCI_Dest);
Args.push_back(BCI_Src);
CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(1), Int64Ty, false, "", I);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst *CI = CallInst::Create(copyTypeInfo, Args);
CI->insertAfter(BCI_Dest);
return true;
} else if(F->getName().str() == std::string("fgets")) {
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value *> Args;
Args.push_back(BCI);
CastInst *Size = CastInst::CreateIntegerCast(CS.getArgument(1), Int64Ty, false, "", I);
Args.push_back(Size);
Args.push_back(getTagCounter());
CallInst::Create(trackInitInst, Args, "", I);
return true;
} else if(F->getName().str() == std::string("snprintf") ||
F->getName().str() == std::string("vsnprintf")) {
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value*>Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
Constant *F = M.getOrInsertFunction("trackgetcwd", VoidTy, VoidPtrTy, Int32Ty, NULL);
CallInst *CINew = CallInst::Create(F, Args);
CINew->insertAfter(I);
} else if(F->getName().str() == std::string("sprintf")) {
Value *BCI = castTo(CS.getArgument(0), VoidPtrTy, "", I);
std::vector<Value*>Args;
Args.push_back(BCI);
CastInst *Size = CastInst::CreateIntegerCast(I, Int64Ty, false);
Size->insertAfter(I);
Instruction *NewValue = BinaryOperator::Create(BinaryOperator::Add,
Size,
One);
NewValue->insertAfter(Size);
Args.push_back(NewValue);
Args.push_back(getTagCounter());
CallInst *CINew = CallInst::Create(trackInitInst, Args);
CINew->insertAfter(NewValue);
} else if(F->getName().str() == std::string("scanf")) {
unsigned i = 1;
while(i < CS.arg_size()) {
visitInputFunctionValue(M, CS.getArgument(i), I);
i++;
}
} else if(F->getName().str() == std::string("sscanf")) {
// FIXME: Need to look at the format string and check
unsigned i = 2;
while(i < CS.arg_size()) {
visitInputFunctionValue(M, CS.getArgument(i), I);
i++;
}
} else if(F->getName().str() == std::string("fscanf")) {
unsigned i = 2;
while(i < CS.arg_size()) {
visitInputFunctionValue(M, CS.getArgument(i), I);
i++;
}
}
} else {
// indirect call site
IndCalls.insert(CS.getInstruction());
return false;
}
return false;
}
// Add extra arguments to each indirect call site
bool TypeChecks::visitIndirectCallSite(Module &M, Instruction *I) {
// add the number of arguments as the first argument
Type* OrigType = I->getOperand(0)->getType();
assert(OrigType->isPointerTy());
FunctionType *FOldType = cast<FunctionType>((cast<PointerType>(OrigType))->getElementType());
std::vector<Type*>TP;
TP.push_back(Int64Ty);
TP.push_back(TypeTagPtrTy);
for(llvm::FunctionType::param_iterator ArgI = FOldType->param_begin(); ArgI != FOldType->param_end(); ++ArgI)
TP.push_back(*ArgI);
FunctionType *FTy = FunctionType::get(FOldType->getReturnType(), TP, FOldType->isVarArg());
Value *Func = castTo(I->getOperand(0), FTy->getPointerTo(), "", I);
inst_iterator InsPt = inst_begin(I->getParent()->getParent());
CallSite CS = CallSite(I);
unsigned int NumArgs = CS.arg_size();
Value *NumArgsVal = ConstantInt::get(Int32Ty, NumArgs);
AllocaInst *AI = new AllocaInst(TypeTagTy, NumArgsVal, "", &*InsPt);
for(unsigned int i = 0; i < CS.arg_size(); i++) {
Value *Idx[1];
Idx[0] = ConstantInt::get(Int32Ty, i-1);
GetElementPtrInst *GEP = GetElementPtrInst::CreateInBounds(AI, Idx, "", I);
Constant *C = getTypeMarkerConstant(CS.getArgument(i));
new StoreInst(C, GEP, I);
}
std::vector<Value *> Args;
Args.push_back(ConstantInt::get(Int64Ty, NumArgs));
Args.push_back(AI);
for(unsigned int i = 0; i < CS.arg_size(); i++)
Args.push_back(CS.getArgument(i));
if(CallInst *CI = dyn_cast<CallInst>(I)) {
CallInst *CI_New = CallInst::Create(Func, Args, "", CI);
CI->replaceAllUsesWith(CI_New);
CI->eraseFromParent();
} else if(InvokeInst *II = dyn_cast<InvokeInst>(I)) {
InvokeInst *INew = InvokeInst::Create(Func,
II->getNormalDest(),
II->getUnwindDest(),
Args,
"", I);
II->replaceAllUsesWith(INew);
II->eraseFromParent();
}
return true;
}
bool TypeChecks::visitInputFunctionValue(Module &M, Value *V, Instruction *CI) {
// Cast the pointer operand to i8* for the runtime function.
Value *BCI = castTo(V, VoidPtrTy, "", CI);
PointerType *PTy = dyn_cast<PointerType>(V->getType());
if(!PTy)
return false;
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getTypeMarkerConstant(PTy->getElementType()));
Args.push_back(getSizeConstant(PTy->getElementType()));
Args.push_back(getTagCounter());
// Create the call to the runtime check and place it before the store instruction.
CallInst::Create(trackStoreInst, Args, "", CI);
if(PTy == VoidPtrTy) {
// TODO: This is currently a heuristic for strings. If we see a i8* in a call to
// input functions, treat as string, and get length using strlen.
std::vector<Value*> Args;
Args.push_back(BCI);
Args.push_back(getTagCounter());
CallInst *CINew = CallInst::Create(trackStringInput, Args);
CINew->insertAfter(CI);
}
return true;
}
// Insert runtime checks before all load instructions.
bool TypeChecks::visitLoadInst(Module &M, LoadInst &LI) {
inst_iterator InsPt = inst_begin(LI.getParent()->getParent());
// Cast the pointer operand to i8* for the runtime function.
Value *BCI = castTo(LI.getPointerOperand(), VoidPtrTy, "", &LI);
Value *Size = ConstantInt::get(Int32Ty, getSize(LI.getType()));
AllocaInst *AI = new AllocaInst(TypeTagTy, Size, "", &*InsPt);
std::vector<Value *>Args1;
Args1.push_back(BCI);
Args1.push_back(getSizeConstant(LI.getType()));
Args1.push_back(AI);
Args1.push_back(getTagCounter());
CallInst *getTypeCall = CallInst::Create(getTypeTag, Args1, "", &LI);
if(TrackAllLoads) {
std::vector<Value *> Args;
Args.push_back(getTypeMarkerConstant(&LI));
Args.push_back(getSizeConstant(LI.getType()));
Args.push_back(AI);
Args.push_back(BCI);
Args.push_back(getTagCounter());
CallInst::Create(checkTypeInst, Args, "", &LI);
}
visitUses(&LI, AI, BCI);
if(AI->hasOneUse()) {
// No uses needed checks
getTypeCall->eraseFromParent();
}
// Create the call to the runtime check and place it before the load instruction.
numLoadChecks++;
return true;
}
// AI - metadata
// BCI - ptr
// I - instruction whose uses to instrument
bool TypeChecks::visitUses(Instruction *I, Instruction *AI, Value *BCI) {
for(Value::user_iterator II = I->user_begin(); II != I->user_end(); ++II) {
if(DisablePtrCmpChecks) {
if(isa<CmpInst>(*II)) {
if(I->getType()->isPointerTy())
continue;
}
}
std::vector<Value *> Args;
Args.push_back(getTypeMarkerConstant(I));
Args.push_back(getSizeConstant(I->getType()));
Args.push_back(AI);
Args.push_back(BCI);
Args.push_back(getTagCounter());
if(StoreInst *SI = dyn_cast<StoreInst>(*II)) {
if(SI->getOperand(0) == I) {
// Cast the pointer operand to i8* for the runtime function.
Value *BCI_Dest = castTo(SI->getPointerOperand(), VoidPtrTy, "", SI);
std::vector<Value *> Args;
Args.push_back(BCI_Dest);
Args.push_back(AI);
Args.push_back(getSizeConstant(SI->getOperand(0)->getType()));
Args.push_back(getTypeMarkerConstant(SI->getOperand(0)->getType()));
Args.push_back(BCI);
Args.push_back(getTagCounter());
// Create the call to the runtime check and place it before the copying store instruction.
CallInst::Create(setTypeInfo, Args, "", SI);
} else {
CallInst::Create(checkTypeInst, Args, "", cast<Instruction>(II.getUse().getUser()));
}
} else if(SelectInst *SelI = dyn_cast<SelectInst>(*II)) {
if(SelI->getOperand(0) == I) {
CallInst::Create(checkTypeInst, Args, "", cast<Instruction>(II.getUse().getUser()));
// if it is used as the condition, just insert a check
} else {
SelectInst *Prev = NULL;
SelectInst *PrevBasePtr = NULL;
if(SelectInst_MD_Map.find(SelI) != SelectInst_MD_Map.end()) {
Prev = SelectInst_MD_Map[SelI];
PrevBasePtr = SelectInst_BasePtr_Map[SelI];
}
SelectInst *AI_New;
SelectInst *BCI_New;
if(SelI->getTrueValue() == I) {
if(!Prev) {
AI_New = SelectInst::Create(SelI->getCondition(), AI, Constant::getNullValue(AI->getType()), "", SelI);
BCI_New = SelectInst::Create(SelI->getCondition(), BCI, Constant::getNullValue(BCI->getType()), "", SelI);
} else {
AI_New = SelectInst::Create(SelI->getCondition(), AI, Prev->getFalseValue(), "", SelI);
BCI_New = SelectInst::Create(SelI->getCondition(), BCI, Prev->getFalseValue(), "", SelI);
Prev->replaceAllUsesWith(AI_New);
PrevBasePtr->replaceAllUsesWith(BCI_New);
}
}
else {
if(!Prev) {
AI_New = SelectInst::Create(SelI->getCondition(), Constant::getNullValue(AI->getType()), AI, "", SelI);
BCI_New = SelectInst::Create(SelI->getCondition(), Constant::getNullValue(BCI->getType()), BCI, "", SelI);
} else {
AI_New = SelectInst::Create(SelI->getCondition(), Prev->getTrueValue(), AI, "", SelI);
BCI_New = SelectInst::Create(SelI->getCondition(), Prev->getTrueValue(), BCI, "", SelI);
Prev->replaceAllUsesWith(AI_New);
PrevBasePtr->replaceAllUsesWith(BCI_New);
}
}
SelectInst_MD_Map[SelI] = AI_New;
SelectInst_BasePtr_Map[SelI] = BCI_New;
if(!Prev)
visitUses(SelI, AI_New, BCI_New);
}
} else if(PHINode *PH = dyn_cast<PHINode>(*II)) {
PHINode *Prev = NULL;
PHINode *PrevBasePtr = NULL;
if(PHINode_MD_Map.find(PH) != PHINode_MD_Map.end()) {
Prev = PHINode_MD_Map[PH];
PrevBasePtr = PHINode_BasePtr_Map[PH];
}
if(InsertedPHINodes.find(PH) != InsertedPHINodes.end())
continue;
/*if(isa<PHINode>(I)) {
std::string name = PH->getName();
if (strncmp(name.c_str(), "baseptr.", 8) == 0) continue;
}*/
PHINode *AI_New;
PHINode *BCI_New;
if(!Prev) {
AI_New = PHINode::Create(AI->getType(),
PH->getNumIncomingValues(),
PH->getName().str() + ".md",
PH);
BCI_New = PHINode::Create(BCI->getType(),
PH->getNumIncomingValues(),
PH->getName().str() + ".baseptr",
PH);
for(unsigned c = 0; c < PH->getNumIncomingValues(); c++) {
if(PH->getIncomingValue(c) == I) {
AI_New->addIncoming(AI, PH->getIncomingBlock(c));
BCI_New->addIncoming(BCI, PH->getIncomingBlock(c));
}
else {
AI_New->addIncoming(Constant::getNullValue(AI->getType()), PH->getIncomingBlock(c));
BCI_New->addIncoming(Constant::getNullValue(BCI->getType()), PH->getIncomingBlock(c));
}
}
PHINode_MD_Map[PH] = AI_New;
PHINode_BasePtr_Map[PH] = BCI_New;
InsertedPHINodes.insert(AI_New);
InsertedPHINodes.insert(BCI_New);
visitUses(PH, AI_New, BCI_New);
}
else {
for(unsigned c = 0; c < PH->getNumIncomingValues(); c++) {
if(PH->getIncomingValue(c) == I) {
Prev->setIncomingValue(c, AI);
PrevBasePtr->setIncomingValue(c, BCI);
}
}
}
} else if(BitCastInst *BI = dyn_cast<BitCastInst>(*II)) {
BitCast_MD_Map[BI] = AI;
visitUses(BI, AI, BCI);
//CallInst::Create(checkTypeInst, Args.begin(), Args.end(), "", cast<Instruction>(II.getUse().getUser()));
/*} else if(PtrToIntInst *P2I = dyn_cast<PtrToIntInst>(II)) {
visitUses(P2I, AI, BCI);
} else if(IntToPtrInst *I2P = dyn_cast<IntToPtrInst>(II)) {
visitUses(I2P, AI, BCI);*/
}else {
CallInst::Create(checkTypeInst, Args, "", cast<Instruction>(II.getUse().getUser()));
}
}
return true;
}
// Insert runtime checks before all store instructions.
bool TypeChecks::visitStoreInst(Module &M, StoreInst &SI) {
if(isa<LoadInst>(SI.getOperand(0)->stripPointerCasts())) {
return false;
}
if(PHINode *PH = dyn_cast<PHINode>(SI.getOperand(0)->stripPointerCasts())) {
if(PHINode_MD_Map.find(PH) != PHINode_MD_Map.end())
return false;
}
if(SelectInst *SelI = dyn_cast<SelectInst>(SI.getOperand(0)->stripPointerCasts())) {
if(SelectInst_MD_Map.find(SelI) != SelectInst_MD_Map.end())
return false;
}
if(BitCastInst *BI = dyn_cast<BitCastInst>(SI.getOperand(0)->stripPointerCasts())) {
if(BitCast_MD_Map.find(BI) != BitCast_MD_Map.end())
return false;
}
// Cast the pointer operand to i8* for the runtime function.
Value *BCI = castTo(SI.getPointerOperand(), VoidPtrTy, "", &SI);
std::vector<Value *> Args;
Args.push_back(BCI);
Args.push_back(getTypeMarkerConstant(SI.getOperand(0))); // SI.getValueOperand()
Args.push_back(getSizeConstant(SI.getOperand(0)->getType()));
Args.push_back(getTagCounter());
// Create the call to the runtime check and place it before the store instruction.
CallInst::Create(trackStoreInst, Args, "", &SI);
numStoreChecks++;
return true;
}