This commit was manufactured by cvs2svn to create tag 'start'.
llvm-svn: 87109
diff --git a/safecode/Makefile b/safecode/Makefile
new file mode 100755
index 0000000..6698a54
--- /dev/null
+++ b/safecode/Makefile
@@ -0,0 +1,7 @@
+LEVEL = .
+DIRS = lib tools
+
+include $(LEVEL)/Makefile.common
+
+test :: all
+ cd test; $(MAKE)
diff --git a/safecode/Makefile.common b/safecode/Makefile.common
new file mode 100755
index 0000000..052feab
--- /dev/null
+++ b/safecode/Makefile.common
@@ -0,0 +1,16 @@
+# should be llvm source
+LLVM_SRC_DIR = /home/vadve/dhurjati/llvmnew/llvm
+
+# project directory
+PROJ_DIR = /home/vadve/$(USER)/parse
+
+#llvm lib
+LLVM_LIB_DIR = /localhome/$(USER)/llvmnew/llvm/
+
+#proj compile
+PROJ_COMPILE := 1
+
+TOPLEVEL := $(LEVEL)
+LEVEL = $(LLVM_SRC_DIR)
+include $(LEVEL)/Makefile.common
+
diff --git a/safecode/README b/safecode/README
new file mode 100755
index 0000000..2b2fa73
--- /dev/null
+++ b/safecode/README
@@ -0,0 +1 @@
+Need to change a few definitions in Makefile to use the Makefile
diff --git a/safecode/include/ArrayBoundsCheck.h b/safecode/include/ArrayBoundsCheck.h
new file mode 100755
index 0000000..619810c
--- /dev/null
+++ b/safecode/include/ArrayBoundsCheck.h
@@ -0,0 +1,2 @@
+Pass *createABCPreProcessPass();
+Pass *createArrayBoundsCheckPass();
diff --git a/safecode/include/SafeDynMemAlloc.h b/safecode/include/SafeDynMemAlloc.h
new file mode 100755
index 0000000..0d6a357
--- /dev/null
+++ b/safecode/include/SafeDynMemAlloc.h
@@ -0,0 +1,15 @@
+//===- llvm/Transforms/IPO/EmbeC/EmbeC.h - CZero passes -*- C++ -*---------=//
+//
+// This file defines a set of utilities for EmbeC checks on pointers and
+// dynamic memory
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EMBEC_H
+#define LLVM_EMBEC_H
+
+#include "llvm/Pass.h"
+
+Pass* createEmbeCFreeRemovalPass();
+
+#endif
diff --git a/safecode/include/StackSafety.h b/safecode/include/StackSafety.h
new file mode 100755
index 0000000..585f113
--- /dev/null
+++ b/safecode/include/StackSafety.h
@@ -0,0 +1,14 @@
+//===- StackSafety.h -*- C++ -*---------=//
+//
+// This file defines checks for stack safety
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_STACKSAFETY_H
+#define LLVM_STACKSAFETY_H
+
+#include "llvm/Pass.h"
+
+Pass* createStackSafetyPass();
+
+#endif
diff --git a/safecode/include/UninitPointer.h b/safecode/include/UninitPointer.h
new file mode 100755
index 0000000..7403143
--- /dev/null
+++ b/safecode/include/UninitPointer.h
@@ -0,0 +1,17 @@
+//===- llvm/Transforms/IPO/CZero/CZero.h - CZero passes -*- C++ -*---------=//
+//
+// This file defines a set of utilities for CZero checks on pointers and
+// dynamic memory
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CZERO_H
+#define LLVM_CZERO_H
+
+#include "llvm/Pass.h"
+
+
+FunctionPass* createCZeroUninitPtrPass();
+// FunctionPass* createCZeroLivePtrs();
+
+#endif
diff --git a/safecode/lib/ArrayBoundChecks/ABCPreProcess.cpp b/safecode/lib/ArrayBoundChecks/ABCPreProcess.cpp
new file mode 100755
index 0000000..f4edbb5
--- /dev/null
+++ b/safecode/lib/ArrayBoundChecks/ABCPreProcess.cpp
@@ -0,0 +1,81 @@
+//===- ArrayBoundCheck.cpp - ArrayBounds Checking (Omega)----------------===//
+//
+// requires piNodeinsertion pass before
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/BasicBlock.h"
+#include "AffineExpressions.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Instruction.h"
+#include "llvm/Constants.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
+
+namespace ABC {
+
+ IndVarMap indMap;
+ ExitNodeMap enMap;
+ PostDominanceFrontier * pdf;
+ DominatorSet *ds;
+ PostDominatorSet *pds;
+
+ //This pass is written because the induction var pass doesnt run properly
+ //after the phi nodes are inserted.
+ struct ABCPreProcess : public FunctionPass {
+ private:
+ void print(ostream &out);
+
+ public :
+ const char *getPassName() const { return "Collect Induction Variables"; }
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<UnifyFunctionExitNodes>();
+ AU.addRequired<LoopInfo>();
+ AU.addRequired<DominatorSet>();
+ AU.addRequired<PostDominatorSet>();
+ AU.addRequired<PostDominanceFrontier>();
+ }
+ virtual bool runOnFunction(Function &F);
+ };
+
+
+
+
+void ABCPreProcess::print(ostream &out) {
+ out << " Printing phi nodes which are induction variables ... \n";
+ IndVarMap::iterator ivCurrent = indMap.begin(), ivEnd = indMap.end();
+ for (; ivCurrent != ivEnd; ++ivCurrent) {
+ out << ivCurrent->first;
+ }
+ out << " Printing induction variables done ... \n";
+
+}
+
+bool ABCPreProcess::runOnFunction(Function &F) {
+ BasicBlock *bb = getAnalysis<UnifyFunctionExitNodes>().getExitNode();
+ enMap[&F] = bb;
+ LoopInfo &LI1 = getAnalysis<LoopInfo>();
+ LoopInfo *LI = & LI1;
+
+ pdf = &getAnalysis<PostDominanceFrontier>();
+ ds = &getAnalysis<DominatorSet>();
+ pds = &getAnalysis<PostDominatorSet>();
+ // std::cerr << "calculated pdf for " << F.getName() << "\n";
+ for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
+ if (PHINode *phi = dyn_cast<PHINode>(*I)) {
+ InductionVariable* iv = new InductionVariable(phi,LI);
+ indMap[phi] = iv;
+ }
+ }
+ // print(std::cerr);
+ return false;
+}
+
+ RegisterOpt<ABCPreProcess> Y("abcpre",
+ "Array Bounds Checking preprocess pass");
+
+}
+
+Pass *createABCPreProcessPass() { return new ABC::ABCPreProcess(); }
diff --git a/safecode/lib/ArrayBoundChecks/AffineExpressions.cpp b/safecode/lib/ArrayBoundChecks/AffineExpressions.cpp
new file mode 100755
index 0000000..83bb594
--- /dev/null
+++ b/safecode/lib/ArrayBoundChecks/AffineExpressions.cpp
@@ -0,0 +1,171 @@
+//===- Expressions.cpp - Expression Analysis Utilities ----------------------=//
+//
+// This file defines a package of expression analysis utilties:
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "AffineExpressions.h"
+#include "llvm/SlotCalculator.h"
+#include "llvm/DerivedTypes.h"
+#include "Support/StringExtras.h"
+#include "llvm/ConstantHandling.h"
+#include "llvm/Function.h"
+#include "llvm/BasicBlock.h"
+#include "llvm/InstrTypes.h"
+#include "llvm/iTerminators.h"
+#include "llvm/iMemory.h"
+#include "llvm/iOther.h"
+#include "llvm/iPHINode.h"
+#include "llvm/BasicBlock.h"
+#include <iostream>
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/InductionVariable.h"
+
+
+
+LinearExpr::LinearExpr(const Value *Val, SlotCalculator &Tab) {
+ if (Val) {
+ vList = new VarList();
+ cMap = new CoefficientMap();
+ vsMap = new ValStringMap();
+ if (const ConstantSInt *CPI = dyn_cast<ConstantSInt>(Val)) {
+ offSet = CPI->getValue();
+ exprTy = Linear;
+ return;
+ } else if (const ConstantUInt *CPI = dyn_cast<ConstantUInt>(Val)) {
+ offSet = CPI->getValue();
+ exprTy = Linear;
+ return;
+ }
+ offSet = 0;
+ vList->push_back(Val);
+ string tempstr;
+ if (Val->hasName()) {
+ tempstr = makeNameProper(Val->getName());
+ } else {
+ int Slot = Tab.getValSlot(Val); // slot number
+ if (Slot >= 0) {
+ tempstr = "l_" + itostr(Slot) + "_" + utostr(Val->getType()->getUniqueID());
+ } else {
+ exprTy = Unknown;
+ tempstr = "unknown";
+ return;
+ }
+ }
+ (*vsMap)[Val] = tempstr;
+ (*cMap)[Val] = 1;
+ }
+ else exprTy = Unknown;
+}
+
+
+void
+LinearExpr::negate() {
+ mulByConstant(-1);
+}
+
+
+void
+LinearExpr::print(ostream &out) {
+
+ if (exprTy != Unknown) {
+ VarListIt vlj = vList->begin();
+ out << offSet;
+ for (; vlj != vList->end(); ++vlj)
+ out << " + " << (*cMap)[*vlj] << " * " << (*vsMap)[*vlj];
+ } else out << "Unknown ";
+}
+
+void
+LinearExpr::addLinearExpr(LinearExpr *E) {
+ if (E->getExprType() == Unknown) {
+ exprTy = Unknown;
+ return;
+ }
+ offSet = E->getOffSet() + offSet;
+ VarList* vl = E->getVarList();
+ CoefficientMap* cm = E->getCMap();
+ ValStringMap* vsm = E->getVSMap();
+
+ VarListIt vli = vl->begin();
+ bool matched;
+ for (; vli != vl->end(); ++vli) {
+ matched = false;
+ VarListIt vlj = vList->begin();
+ for (; vlj != vList->end(); ++vlj) {
+ if (*vli == *vlj) {
+ //matched the vars .. now add the coefficients.
+ (*cMap)[*vli] = (*cMap)[*vli] + (*cm)[*vlj];
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ //didnt match any var....
+ vList->push_back(*vli);
+ (*cMap)[*vli] = (*cm)[*vli];
+ (*vsMap)[*vli] = (*vsm)[*vli];
+ }
+ }
+}
+
+LinearExpr *
+LinearExpr::mulLinearExpr(LinearExpr *E) {
+ if ((exprTy == Unknown) || (E->getExprType() == Unknown)) {
+ exprTy = Unknown;
+ return this;
+ }
+ VarList* vl = E->getVarList();
+ if ((vl->size() != 0) && (vList->size() != 0)) {
+ exprTy = Unknown;
+ return this;
+ }
+ if (vl->size() == 0) {
+ //The one coming in is a constant
+ mulByConstant(E->getOffSet());
+ return this;
+ } else {
+ E->mulByConstant(offSet);
+ return E;
+ }
+}
+
+void
+LinearExpr::mulByConstant(int E) {
+ offSet = offSet * E;
+ VarListIt vlj = vList->begin();
+ for (; vlj != vList->end(); ++vlj) {
+ (*cMap)[*vlj] = (*cMap)[*vlj] * E;
+ }
+}
+
+void
+Constraint::print(ostream &out) {
+ out << var;
+ out << rel;
+ le->print(out);
+}
+
+
+void
+ABCExprTree::print(ostream &out) {
+ if (constraint != 0) {
+ // out << "printing the constraint \n";
+ constraint->print(out);
+ }
+ else {
+ if (logOp == "||")
+ out << "((";
+ left->print(out);
+ if (logOp == "||")
+ out << ") ";
+ out << "\n" << logOp;
+ if (logOp == "||")
+ out << "(";
+ right->print(out);
+ if (logOp == "||")
+ out << "))";
+ }
+}
+
diff --git a/safecode/lib/ArrayBoundChecks/AffineExpressions.h b/safecode/lib/ArrayBoundChecks/AffineExpressions.h
new file mode 100755
index 0000000..6f4846c
--- /dev/null
+++ b/safecode/lib/ArrayBoundChecks/AffineExpressions.h
@@ -0,0 +1,228 @@
+//===- llvm/ArrayBoundChecks/AffineExpressions.h - Expression Analysis Utils ---*- C++ -*--=//
+//
+// This file defines a package of expression analysis utilties:
+//
+
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_C_EXPRESSIONS_H
+#define LLVM_C_EXPRESSIONS_H
+
+#include <assert.h>
+#include <map>
+#include <list>
+#include <string>
+#include "llvm/Instruction.h"
+#include "llvm/iMemory.h"
+#include "llvm/InstrTypes.h"
+#include "llvm/iTerminators.h"
+#include "llvm/iOther.h"
+#include "llvm/iPHINode.h"
+#include "llvm/iOperators.h"
+#include "llvm/Constants.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "Support/StringExtras.h"
+#include "llvm/SlotCalculator.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Analysis/InductionVariable.h"
+
+using namespace std;
+
+class Value;
+class BasicBlock;
+class Function;
+
+namespace cfg { class LoopInfo; }
+
+typedef std::map<const PHINode *,InductionVariable*> IndVarMap;
+typedef std::map<const Function *,BasicBlock *> ExitNodeMap;
+typedef std::map<const Function *, PostDominanceFrontier *> PostDominanceFrontierMap;
+
+typedef std::map<const Value*,int> CoefficientMap;
+typedef std::map<const Value*,string> ValStringMap;
+typedef std::list<const Value*> VarList;
+typedef std::list<const Value*>::const_iterator VarListIt;
+typedef std::list<const CallInst*> CallInstList;
+typedef std::list<const CallInst*>::const_iterator CallInstListIt;
+typedef std::list<const Instruction*> MemAccessInstListType;
+typedef std::list<const Instruction*>::const_iterator MemAccessInstListIt;
+
+// LinearExpr - Represent an expression of the form CONST*VAR1+CONST*VAR2+ .....
+// or simpler.
+
+
+class LinearExpr {
+
+ int offSet;
+ VarList* vList;
+ CoefficientMap* cMap;
+ ValStringMap* vsMap;
+public:
+enum ExpressionType {
+ Linear, // Expr is linear
+ Unknown
+ } exprTy;
+ inline int getOffSet() { return offSet; };
+ inline void setOffSet(int offset) { offSet = offset; };
+ inline ExpressionType getExprType() { return exprTy; };
+ inline VarList* getVarList() { return vList; };
+ inline CoefficientMap* getCMap() { return cMap; };
+ inline ValStringMap* getVSMap() { return vsMap; };
+
+ LinearExpr(const Value *Val,SlotCalculator &Tab); // Create a linear expression
+ void negate();
+ void addLinearExpr(LinearExpr *);
+ LinearExpr * mulLinearExpr(LinearExpr *);
+ void mulByConstant(int);
+ void print(ostream &out);
+};
+
+class Constraint {
+ string var;
+ LinearExpr *le;
+ string rel; // can be < , >, <=, >= for now
+public :
+ Constraint(string v, LinearExpr *l, string r) {
+ assert(l != 0 && "the rhs for this constraint is null");
+ var = v;
+ le = l;
+ rel = r;
+ }
+ void print(ostream &out);
+};
+
+
+
+//This holds a set of ABCExprs
+class ABCExprTree {
+ Constraint *constraint;
+ ABCExprTree *right;
+ ABCExprTree *left;
+ string logOp; // can be && or || or
+ public:
+ ABCExprTree(Constraint *c) {
+ constraint = c;
+ left = 0;
+ right = 0;
+ logOp = "&&";
+ };
+ ABCExprTree(ABCExprTree *l, ABCExprTree *r, string op) {
+ constraint = 0;
+ left = l;
+ right = r;
+ logOp = op;
+ }
+ void print(ostream &out);
+};
+
+typedef std::map<const Value *, ABCExprTree *> InstConstraintMapType;
+
+
+
+//This holds the local information of a function
+class FuncLocalInfo {
+ //Local cache for constraints
+ InstConstraintMapType FuncLocalConstraints;
+
+ //Storing all constraints which need proving
+ InstConstraintMapType FuncSafetyConstraints;
+
+ //All array accesses in a function
+ MemAccessInstListType maiList;
+ //This stores the Or of the arguments at
+ //various call sites, so that can be computed only once for
+ //different array accesses.
+ ABCExprTree *argConstraints;
+
+ bool dependsOnArg;
+public :
+ FuncLocalInfo() {
+ dependsOnArg = false;
+ argConstraints = 0;
+ }
+
+ inline void setdependsOnArg() {
+ dependsOnArg = true;
+ }
+
+ inline bool isDependentOnArg() {
+ return dependsOnArg;
+ }
+
+ inline void addMemAccessInst(Instruction *MAI) {
+ maiList.push_back(MAI);
+ }
+
+ inline void addLocalConstraint(const Value *v, ABCExprTree *aet) {
+ FuncLocalConstraints[v] = aet;
+ }
+ inline bool inLocalConstraints(const Value *v) {
+ return (FuncLocalConstraints.count(v) > 0);
+ }
+ inline ABCExprTree * getLocalConstraint(const Value *v) {
+ if (FuncLocalConstraints.count(v)) return FuncLocalConstraints[v];
+ else return 0;
+ }
+ inline void addSafetyConstraint(const Value *v, ABCExprTree *aet) {
+ FuncSafetyConstraints[v] = aet;
+ }
+ inline ABCExprTree* getSafetyConstraint(const Value *v) {
+ return (FuncSafetyConstraints[v]);
+ }
+ inline MemAccessInstListType getMemAccessInstList() {
+ return maiList;
+ }
+
+ inline void addArgumentConstraints(ABCExprTree *aet) {
+ argConstraints = aet;
+ }
+ inline ABCExprTree * getArgumentConstraints() {
+ return argConstraints;
+ }
+};
+
+// We dont want identifier names with ., space, - in them.
+// So we replace them with _
+static string makeNameProper(string x) {
+ string tmp;
+ int len = 0;
+ for (string::iterator sI = x.begin(), sEnd = x.end(); sI != sEnd; sI++) {
+ if (len > 18) return tmp; //have to do something more meaningful
+ len++;
+ switch (*sI) {
+ case '.': tmp += "d_"; len++;break;
+ case ' ': tmp += "s_"; len++;break;
+ case '-': tmp += "D_"; len++;break;
+ case '_': tmp += "l_"; len++;break;
+ default: tmp += *sI;
+ }
+ }
+ if (tmp == "in") return "in__1";
+ return tmp;
+ };
+
+
+static string getValueNames( Value *V, SlotCalculator *Table) {
+ if ( Constant *CPI = dyn_cast<Constant>(V)) {
+ if ( ConstantSInt *CPI = dyn_cast<ConstantSInt>(V)) {
+ return itostr(CPI->getValue());
+ } else if ( ConstantUInt *CPI = dyn_cast<ConstantUInt>(V)) {
+ return utostr(CPI->getValue());
+ }
+ }
+ if (V->hasName()) {
+ return makeNameProper(V->getName());
+ }
+ else {
+ int Slot = Table->getValSlot(V);
+ // assert(Slot >= 0 && "Invalid value!");
+ if (Slot >= 0) {
+ return "l_" + itostr(Slot) + "_" + utostr(V->getType()->getUniqueID());
+ } else return "Unknown";
+ }
+};
+
+
+
+#endif
diff --git a/safecode/lib/ArrayBoundChecks/ArrayBoundCheck.cpp b/safecode/lib/ArrayBoundChecks/ArrayBoundCheck.cpp
new file mode 100755
index 0000000..435c693
--- /dev/null
+++ b/safecode/lib/ArrayBoundChecks/ArrayBoundCheck.cpp
@@ -0,0 +1,1030 @@
+//===- ArrayBoundCheck.cpp - ArrayBounds Checking (Omega)----------------===//
+//
+// requires piNodeinsertion pass before
+// Now we use the control dependence
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/BasicBlock.h"
+#include "AffineExpressions.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Instruction.h"
+#include "llvm/Constants.h"
+#include "llvm/Analysis/InductionVariable.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
+#include <fstream>
+
+#define REGION_INIT "RInit"
+#define REGION_MALLOC "RMalloc"
+#define REGION_FREE "RFree"
+
+namespace ABC{
+ static std::ofstream out("omega.ip");
+
+ //these are filled from preprocess pass, since they require fn passes
+ //FIXME replace these by annotations later.
+ extern IndVarMap indMap;
+ extern ExitNodeMap enMap;
+ extern PostDominanceFrontier* pdf;
+ extern DominatorSet* ds;
+ extern PostDominatorSet* pds;
+
+ static unsigned count = 0;
+ //Interprocedural ArrayBoundsCheck pass
+ struct ArrayBoundsCheck : public Pass {
+ public :
+ const char *getPassName() const { return "Array Bounds Check"; }
+ virtual bool run(Module &M);
+ private :
+ typedef std::map<const Function *,FuncLocalInfo*> InfoMap;
+ typedef std::map<Function*, int> FuncIntMap;
+
+ //This is required for getting the names/unique identifiers for variables.
+ SlotCalculator *Table;
+
+ //for storing local information about a function
+ InfoMap fMap;
+
+ //Known Func Database
+ std::set<string> KnownFuncDB;
+
+ //for storing info about the functions which are already proven safe
+ FuncIntMap provenSafe;
+
+ //for storing what control dependent blocks are already dealt with for the current
+ //array access
+ std::set<BasicBlock *> DoneList;
+
+ //Initializes the KnownFuncDB
+ void initialize();
+
+ void outputDeclsForOmega(Module &M);
+
+ //Interface for collecting constraints for different array access
+ // in a function
+ void collectSafetyConstraints(Function &F);
+
+ //This function collects from the branch which controls the current block
+ //the Successor tells the path
+ void addBranchConstraints(BranchInst *BI, BasicBlock *Successor, ABCExprTree **rootp);
+ //This method adds constraints for known trusted functions
+ void addConstraintsForKnownFunctions(CallInst *CI, ABCExprTree **rootp);
+
+
+ //Interface for getting constraints for a particular value
+ void getConstraintsInternal( Value *v, ABCExprTree **rootp);
+ void getConstraints( Value *v, ABCExprTree **rootp);
+
+ //adds all the conditions on which the currentblock is control dependent on.
+ void addControlDependentConditions(BasicBlock *currentBlock, ABCExprTree **rootp);
+
+ //Gives the return value constraints interms of its arguments
+ void getReturnValueConstraints( const CallInst *CI,ABCExprTree **rootp);
+
+ //Checks if the function is safe (produces output for omega consumption)
+ void checkSafety(Function &F, ostream &out);
+
+ //Get the constraints on the arguments
+ //This goes and looks at all call sites and ors the corresponding
+ //constraints
+ ABCExprTree* getArgumentConstraints(Function &F);
+
+ //for simplifying the constraints
+ LinearExpr* SimplifyExpression( Value *Expr, ABCExprTree **rootp);
+
+ string getValueName( Value *V);
+ void generateArrayTypeConstraintsGlobal(string var, const ArrayType *T, ABCExprTree **rootp, unsigned int numElem);
+ void generateArrayTypeConstraints(string var, const ArrayType *T, ABCExprTree **rootp);
+ void printarraytype(string var,const ArrayType *T);
+ void printStandardArguments(const Module *M, ostream & out);
+ };
+
+ void ArrayBoundsCheck::initialize() {
+ KnownFuncDB.insert("puts");
+ KnownFuncDB.insert("memcpy"); //need to add the extra checks
+ // KnownFuncDB.insert("fscanf");
+ KnownFuncDB.insert("strcpy"); //need to add the extra checks
+ KnownFuncDB.insert("strlen");
+ KnownFuncDB.insert("strcmp");
+ KnownFuncDB.insert("strtol");
+ KnownFuncDB.insert("fopen");
+ KnownFuncDB.insert("fwrite");
+ KnownFuncDB.insert("fgetc");
+ KnownFuncDB.insert("getc");
+ KnownFuncDB.insert("read");
+ KnownFuncDB.insert("fread");
+ KnownFuncDB.insert("feof");
+ KnownFuncDB.insert("fputc");
+ KnownFuncDB.insert("qsort"); //need to add the extra checks
+ }
+
+ void ArrayBoundsCheck::outputDeclsForOmega(Module& M) {
+ for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) {
+ Function *F = FI;
+ out << "symbolic Unknown;\n";
+ out << "symbolic argc;\n";
+ out << "symbolic argv;\n";
+ if (!(F->isExternal())) {
+ out << "symbolic " << getValueName(F) <<"; \n";
+ for (Function::ArgumentListType::iterator aI = F->getArgumentList().begin(),
+ aE = F->getArgumentList().end(); aI != aE; ++aI) {
+ out << "symbolic ";
+ out << getValueName((aI));
+ out << ";\n";
+ }
+ }
+ for (Module::giterator gI = M.gbegin(), gE = M.gend(); gI != gE; ++gI) {
+ out << "symbolic ";
+ out << getValueName((gI));
+ out << ";\n";
+ if (const ArrayType *AT = dyn_cast<ArrayType>(gI->getType()->getElementType())) {
+ printarraytype(getValueName(gI), AT);
+ }
+ }
+
+ for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
+ if ((*I)->getType() != Type::VoidTy) {
+ out << "symbolic ";
+ out << getValueName(*I);
+ out << ";\n";
+ if (AllocationInst *AI = dyn_cast<AllocationInst>(*I)) {
+ //FIXME this should be really alloca (for local variables)
+ //This can not be malloc, if array bounds check is run just after
+ //bytecode is generated. But if other passes introduce mallocInsts
+ //we should take care of them just like the allocas
+
+
+ //We have to see the dimension of the array that this alloca is
+ //pointing to
+ //If the allocation is done by constant, then its a constant array
+ // else its a normal alloca which we already have taken care of
+ if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getType()->getElementType())) {
+ printarraytype(getValueName(*I), AT);
+ }
+ } //Note that RMalloc unlike alloca cannot take an array type constant
+ //Array type constant is only taken by alloca for the local variables
+ }
+ }
+ }
+
+
+
+ string ArrayBoundsCheck::getValueName( Value *V) {
+ return getValueNames(V, Table);
+ }
+
+ void ArrayBoundsCheck::printarraytype(string var,const ArrayType *T) {
+ string var1 = var + "_i";
+ out << "symbolic " << var1 << ";\n";
+ if (const ArrayType *AT = dyn_cast<ArrayType>(T->getElementType())) {
+ printarraytype(var1,AT);
+ }
+ }
+
+ //This is an auxillary function used by getConstraints
+ //gets the constraints on the return value interms of its arguments
+ // and ands it with the existing rootp!
+ void ArrayBoundsCheck::getReturnValueConstraints(const CallInst *CI,ABCExprTree **rootp) {
+ // out << "in return value constraints \n";
+ //and the return
+ if (const Function* pf = dyn_cast<Function>(CI->getOperand(0))) {
+ //we have to get the exit node for pf
+ if (KnownFuncDB.find(CI->getOperand(0)->getName()) != KnownFuncDB.end()) {
+ if (!(pf->isExternal())) {
+ BasicBlock *bb = enMap[pf];
+ getConstraints(bb->getTerminator(),rootp);
+ /*
+ if (bb->getTerminator()->getType()->getPrimitiveID() != Type::VoidTyID) {
+ out << "in return value constraints for" << bb->getTerminator() << "\n";
+ }
+ */
+ }
+ }
+ }
+ }
+
+ void ArrayBoundsCheck::addControlDependentConditions(BasicBlock *currentBlock, ABCExprTree **rootp) {
+ PostDominanceFrontier::const_iterator it = pdf->find(currentBlock);
+ if (it != pdf->end()) {
+ const PostDominanceFrontier::DomSetType &S = it->second;
+ if (S.size() > 0) {
+ PostDominanceFrontier::DomSetType::iterator pCurrent = S.begin(), pEnd = S.end();
+ //check if it is control dependent on only one node.
+ //If it is control dependent on only one node.
+ //If it not, then there must be only one that dominates this node and
+ //the rest should be dominated by this node.
+ //or this must dominate every other node (incase of do while)
+ bool dominated = false;
+ bool rdominated = true; //to check if this dominates every other node
+ for (; pCurrent != pEnd; ++pCurrent) {
+ BasicBlock *debugBlock = *pCurrent;
+ if (*pCurrent == currentBlock) {
+ rdominated = rdominated & true;
+ continue;
+ }
+ if (!dominated) {
+ if (ds->dominates(*pCurrent, currentBlock)) {
+ dominated = true;
+ rdominated = false;
+ continue;
+ }
+ }
+ if (ds->dominates(currentBlock, *pCurrent)) {
+ rdominated = rdominated & true;
+ continue;
+ } else {
+ // out << "In function " << currentBlock->getParent()->getName();
+ // out << "for basic block " << currentBlock->getName();
+ // out << "Something wrong .. non affine or unstructured control flow ??\n";
+ dominated = false;
+ break;
+ }
+ }
+ if ((dominated) || (rdominated)) {
+ //Now we are sure that the control dominance is proper
+ //i.e. it doesn't have unstructured control flow
+
+ PostDominanceFrontier::DomSetType::iterator pdCurrent = S.begin(), pdEnd = S.end();
+ for (; pdCurrent != pdEnd; ++pdCurrent) {
+ BasicBlock *CBB = *pdCurrent;
+ if (DoneList.find(CBB) == DoneList.end()) {
+ TerminatorInst *TI = CBB->getTerminator();
+ if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
+ for (unsigned index = 0; index < BI->getNumSuccessors(); ++index) {
+ BasicBlock * succBlock = BI->getSuccessor(index);
+ if (pds->dominates(currentBlock, succBlock)) {
+ // if (BI->getSuccessor(index) == currentBlock) {
+ //FIXME It need not be Successor, we need to check for post dominance
+
+ DoneList.insert(CBB);
+ addControlDependentConditions(CBB,rootp);
+ addBranchConstraints(BI, BI->getSuccessor(index), rootp);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //adds constraints for known functions
+ void ArrayBoundsCheck::addConstraintsForKnownFunctions(CallInst *CI, ABCExprTree **rootp) {
+ string funcName = CI->getOperand(0)->getName();
+ if (funcName == "memcpy") {
+ string var = getValueName(CI->getOperand(1));
+ LinearExpr *l1 = new LinearExpr(CI->getOperand(2),*Table);
+ Constraint *c1 = new Constraint(var,l1,">=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"||");
+ getConstraints(CI->getOperand(1), rootp);
+ getConstraints(CI->getOperand(2), rootp);
+ } else if (funcName == "strlen") {
+ string var = getValueName(CI);
+ const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
+ const ConstantSInt * signedzero = ConstantSInt::get(csiType,0);
+
+ Constraint *c = new Constraint(var, new LinearExpr(signedzero, *Table),">=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+
+
+ string var1 = var +" + 1";
+
+ LinearExpr *l1 = new LinearExpr(CI->getOperand(1),*Table);
+ Constraint *c1 = new Constraint(var1,l1,"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"&&");
+ getConstraints(CI->getOperand(1), rootp);
+ } else if (funcName == "read") {
+ //FIXME we also need to check that the buf size is less than
+ //the bytes reading
+ string var = getValueName(CI);
+ LinearExpr *l1 = new LinearExpr(CI->getOperand(3),*Table);
+ Constraint *c1 = new Constraint(var,l1,"<=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"&&");
+ getConstraints(CI->getOperand(3), rootp);
+
+ } else if (funcName == "fread") {
+ //FIXME we also need to check that the buf size is less than
+ //the bytes reading
+ string var = getValueName(CI);
+ LinearExpr *l1 = new LinearExpr(CI->getOperand(2),*Table);
+ LinearExpr *l2 = new LinearExpr(CI->getOperand(3),*Table);
+ l2->mulLinearExpr(l1);
+ Constraint *c1 = new Constraint(var,l2,"<=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"&&");
+ getConstraints(CI->getOperand(3), rootp);
+ getConstraints(CI->getOperand(2), rootp);
+
+ } else {
+ // out << funcName << " is not supported yet \n";
+ }
+ }
+
+
+ void ArrayBoundsCheck::getConstraints(Value *v, ABCExprTree **rootp) {
+ string tempName1 = getValueName(v);
+ LinearExpr *letemp1 = new LinearExpr(v,*Table);
+ Constraint* ctemp1 = new Constraint(tempName1,letemp1,"=");
+ ABCExprTree* abctemp1 = new ABCExprTree(ctemp1);
+ getConstraintsInternal(v,&abctemp1);
+ *rootp = new ABCExprTree(*rootp, abctemp1, "&&");
+ }
+
+ //Get Constraints on a value v, this assumes that the Table is correctly set
+ //for the function that is cal ling this
+ void ArrayBoundsCheck::getConstraintsInternal(Value *v, ABCExprTree **rootp) {
+ string var;
+ LinearExpr *et;
+ if ( Instruction *I = dyn_cast<Instruction>(v)) {
+
+ Function* func = I->getParent()->getParent();
+ BasicBlock * currentBlock = I->getParent();
+
+ // out << "fn & bb " << func->getName() << I->getParent()->getName() << "\n";
+ // out << " getting constraints for the Instruction " << *I;
+
+
+ //Here we need to add the post dominator stuff if necessary
+ addControlDependentConditions(currentBlock, rootp);
+
+ if (!isa<ReturnInst>(I)) {
+ var = getValueName(I);
+ } else {
+ var = getValueName(func);
+ }
+ if (fMap[func]->inLocalConstraints(I)) { //checking the cache
+ if (fMap[func]->getLocalConstraint(I) != 0) {
+ *rootp = new ABCExprTree(*rootp, fMap[func]->getLocalConstraint(I),"&&");
+ }
+ return;
+ }
+ fMap[func]->addLocalConstraint(I,0);
+ if (isa<SwitchInst>(I)) {
+ //TODO later
+ } else if (ReturnInst * ri = dyn_cast<ReturnInst>(I)) {
+ //For getting the constraints on return values
+ LinearExpr *l1 = new LinearExpr(ri->getOperand(0),*Table);
+ Constraint *c1 = new Constraint(var,l1,"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"&&");
+ if (ri->getNumOperands() > 0) {
+ getConstraints(ri->getOperand(0), rootp);
+ }
+
+ } else if (PHINode *p = dyn_cast<PHINode>(I)) {
+ //its a normal PhiNode
+ if (indMap.count(p) > 0) {
+ InductionVariable* iv = indMap[p];
+ if (iv->InductionType != InductionVariable::Unknown) {
+ //depending on the sign ,
+ // FIXME : for the following assumptions
+ // sign is assumed positive
+ ABCExprTree *abcetemp;
+ Value *v0 = p->getIncomingValue(0);
+ Value *v1 = p->getIncomingValue(1);
+ if (iv->Start != v0) {
+ std::swap(v0, v1);
+ }
+ LinearExpr *l1 = new LinearExpr(v0,*Table);
+ Constraint *c1 = new Constraint(var,l1,">=");
+ Instruction *prevDef;
+ if ((prevDef = dyn_cast<Instruction>(v0))) {
+ getConstraints(prevDef,rootp);
+ };
+ abcetemp = new ABCExprTree(c1);
+
+ //V1 is coming in from the loop
+ l1 = new LinearExpr(v1,*Table);
+ c1 = new Constraint(var,l1,"<=");
+ if ((prevDef = dyn_cast<Instruction>(v1))) {
+ getConstraints(prevDef,rootp);
+ };
+ abcetemp = new ABCExprTree(abcetemp,new ABCExprTree(c1),"&&"); //
+ *rootp = new ABCExprTree(*rootp,abcetemp,"&&");
+ } else {
+ //Its OKay to conservatively ignore this phi node
+ // out << " In function " << I->getParent()->getParent()->getName() << "\n";
+ // out << " for the instruction " << I << "\n";
+ // out << " \n\n Induction Variable not Found \n\n ";
+ // out << "Array Bounds Check failed ";
+ }
+ } else {
+ // out << " \n\n Induction Variable not Found \n\n ";
+ // out << "Array Bounds Check failed ";
+ }
+ } else if (isa<CallInst>(I)) {
+ CallInst * CI = dyn_cast<CallInst>(I);
+ //First we have to check if it is an RMalloc
+ if (CI->getOperand(0)->getName() == REGION_MALLOC) {
+ //It is an RMalloc, we knoe it has only one argument
+ Constraint *c = new Constraint(var, SimplifyExpression(I->getOperand(1),rootp),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ } else {
+ if (KnownFuncDB.find(CI->getOperand(0)->getName()) != KnownFuncDB.end()) {
+ //Its a known and trusted function
+ // we need to add the constraints carefully
+ addConstraintsForKnownFunctions(CI, rootp);
+ } else {
+ //we have to get constraints for arguments.
+ if (fMap.count(func) == 0) {
+ fMap[func] = new FuncLocalInfo();
+ }
+ getReturnValueConstraints(CI, rootp);
+ //getting the constraints on the arguments.
+ if (Function *Fn = dyn_cast<Function>(CI->getOperand(0))) {
+ Function::aiterator formalArgCurrent = Fn->abegin(), formalArgEnd = Fn->aend();
+ for (unsigned i = 1; formalArgCurrent != formalArgEnd; ++formalArgCurrent, ++i) {
+ string varName = getValueName(formalArgCurrent);
+ Value *OperandVal = CI->getOperand(i);
+ LinearExpr *le = new LinearExpr(OperandVal,*Table);
+ Constraint* c1 = new Constraint(varName,le,"=");
+ ABCExprTree *temp = new ABCExprTree(c1);
+ // if (!isa<Constant>(OperandVal)) {
+ getConstraints(OperandVal,&temp);
+ // }
+ *rootp = new ABCExprTree(*rootp, temp, "&&");
+ }
+ }
+ LinearExpr *le1 = new LinearExpr(v,*Table);
+ Constraint *c1 = new Constraint(getValueName(I->getOperand(0)),le1,"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"&&");
+ }
+ }
+ } else if (isa<AllocationInst>(I)) {
+ //Note that this is for the local variables which are converted in to
+ //allocas , we take care of the RMallocs in the CallInst case
+
+ AllocationInst *AI = cast<AllocationInst>(I);
+ if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getType()->getElementType())) {
+ //sometime allocas have some array as their allocating constant !!
+ //We then have to generate constraints for all the dimensions
+ const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,1);
+
+ Constraint *c = new Constraint(var, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ generateArrayTypeConstraints(var, AT, rootp);
+ } else {
+ //This is the general case, where the allocas are allocated by some
+ //variable
+ Constraint *c = new Constraint(var, SimplifyExpression(I->getOperand(0),rootp),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ }
+ } else if (isa<GetElementPtrInst>(I)) {
+
+
+ GetElementPtrInst *GEP = cast<GetElementPtrInst>(I);
+ Value *PointerOperand = I->getOperand(0);
+ if (const PointerType *pType = dyn_cast<PointerType>(PointerOperand->getType()) ){
+ //this is for arrays inside structs
+ if (const StructType *stype = dyn_cast<StructType>(pType->getElementType())) {
+ //getelementptr *key, long 0, ubyte 0, long 18
+ if (GEP->getNumOperands() == 4) {
+ if (const ArrayType *aType = dyn_cast<ArrayType>(stype->getContainedType(0))) {
+ int elSize = aType->getNumElements();
+ if (const ConstantSInt *CSI = dyn_cast<ConstantSInt>(I->getOperand(3))) {
+ elSize = elSize - CSI->getValue();
+ if (elSize == 0) {
+ //Dirty HACK, this doesnt work for more than 2 arrays in a struct!!
+ if (const ArrayType *aType2 = dyn_cast<ArrayType>(stype->getContainedType(1))) {
+ elSize = aType2->getNumElements();
+ }
+ }
+ const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,elSize);
+ Constraint *c = new Constraint(var, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ }
+ }
+ }
+ }
+ }
+ //dunno if this is a special case or need to be generalized
+ //FIXME for now it is a special case.
+ if (I->getNumOperands() == 2) {
+ getConstraints(PointerOperand,rootp);
+ getConstraints(GEP->getOperand(1),rootp);
+ LinearExpr *L1 = new LinearExpr(GEP->getOperand(1), *Table);
+ LinearExpr *L2 = new LinearExpr(PointerOperand, *Table);
+ L1->negate();
+ L1->addLinearExpr(L2);
+ Constraint *c = new Constraint(var, L1,"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ }
+ //This is added for the special case found in the embedded bench marks
+ //Normally GetElementPtrInst is taken care by the getSafetyConstraints
+ //But sometimes you get a pointer to an array x = &x[0]
+ //z = getelementptr x 0 0
+ //getlelementptr z is equivalent to getelementptr x !
+ if (I->getNumOperands() == 3) {
+ if (const PointerType *PT = dyn_cast<PointerType>(PointerOperand->getType())) {
+ if (const ArrayType *AT = dyn_cast<ArrayType>(PT->getElementType())) {
+ if (const ConstantSInt *CSI = dyn_cast<ConstantSInt>(I->getOperand(1))) {
+ if (CSI->getValue() == 0) {
+ if (const ConstantSInt *CSI2 = dyn_cast<ConstantSInt>(I->getOperand(2))) {
+ if (CSI2->getValue() == 0) {
+ //Now add the constraint
+
+ const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,AT->getNumElements());
+ Constraint *c = new Constraint(var, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ Constraint *c = new Constraint(var, SimplifyExpression(I,rootp),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ }
+ fMap[func]->addLocalConstraint(I,*rootp); //storing in the cache
+ } else if (GlobalVariable *GV = dyn_cast<GlobalVariable>(v)) {
+ //Its a global variable...
+ //It could be an array
+ var = getValueName(GV);
+ if (const ArrayType *AT = dyn_cast<ArrayType>(GV->getType()->getElementType())) {
+ const Type* csiType = Type::getPrimitiveType(Type::UIntTyID);
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,1);
+
+ Constraint *c = new Constraint(var, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ generateArrayTypeConstraintsGlobal(var, AT, rootp, 1);
+ }
+ }
+ }
+
+ void ArrayBoundsCheck::generateArrayTypeConstraintsGlobal(string var, const ArrayType *T, ABCExprTree **rootp, unsigned int numElem) {
+ string var1 = var + "_i";
+ const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
+ if (const ArrayType *AT = dyn_cast<ArrayType>(T->getElementType())) {
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,1);
+ Constraint *c = new Constraint(var1, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ generateArrayTypeConstraintsGlobal(var1,AT, rootp, T->getNumElements() * numElem);
+ } else {
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,numElem * T->getNumElements());
+ Constraint *c = new Constraint(var1, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ }
+ }
+
+
+ void ArrayBoundsCheck::generateArrayTypeConstraints(string var, const ArrayType *T, ABCExprTree **rootp) {
+ string var1 = var + "_i";
+ const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,T->getNumElements());
+ Constraint *c = new Constraint(var1, new LinearExpr(signedOne, *Table),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ if (const ArrayType *AT = dyn_cast<ArrayType>(T->getElementType())) {
+ generateArrayTypeConstraints(var1,AT, rootp);
+ }
+ }
+
+ ABCExprTree *ArrayBoundsCheck::getArgumentConstraints(Function & F) {
+ //First check if it is in cache
+ ABCExprTree *root = fMap[&F]->getArgumentConstraints();
+ if (root) {
+ return root;
+ } else {
+ root = 0;
+ ABCExprTree *rootCallInst;
+ //Its not there in cache, so we compute it
+ DoneList.clear();
+ for (Value::use_iterator I = F.use_begin(), E = F.use_end(); I != E; ++I) {
+ User *U = *I;
+ rootCallInst = 0;
+ if (CallInst *CI = dyn_cast<CallInst>(U)) {
+ //we need to AND the constraints on the arguments
+ Function::aiterator formalArgCurrent = F.abegin(), formalArgEnd = F.aend();
+ for (unsigned i = 1; formalArgCurrent != formalArgEnd; ++formalArgCurrent, ++i) {
+ string varName = getValueName(formalArgCurrent);
+ Value *OperandVal = CI->getOperand(i);
+ LinearExpr *le = new LinearExpr(OperandVal,*Table);
+ Constraint* c1 = new Constraint(varName,le,"=");
+ ABCExprTree *temp = new ABCExprTree(c1);
+ if (!isa<Constant>(OperandVal)) {
+ getConstraints(OperandVal,&temp);
+ }
+ if (!rootCallInst) {
+ rootCallInst = temp;
+ } else {
+ rootCallInst = new ABCExprTree(rootCallInst, temp, "&&");
+ }
+ }
+ if (!root) {
+ root = rootCallInst;
+ } else {
+ root = new ABCExprTree(root, rootCallInst, "||");
+ }
+ }
+ }
+ }
+ fMap[&F]->addArgumentConstraints(root); //store it in cache
+ return root;
+ }
+
+
+ void ArrayBoundsCheck::printStandardArguments(const Module *M, ostream & out) {
+ for (Module::const_iterator fI = M->begin(), fE = M->end(); fI != fE; ++fI) {
+ if (fI->getName() == "main") {
+ Function::const_aiterator formalArgCurrent = fI->abegin(), formalArgEnd = fI->aend();
+ if (formalArgCurrent != formalArgEnd) {
+ //relyingon front end's ability to get two arguments
+ string argcname = formalArgCurrent->getName();
+ ++formalArgCurrent;
+ string argvname = formalArgCurrent->getName();
+ out << " && " << argcname << " = " << argvname ;
+ break;
+ }
+ }
+ }
+ }
+
+
+ //FIXME doesn't handle any kind of recursion
+ void ArrayBoundsCheck::checkSafety(Function &F, ostream &out) {
+ // out << "fn name " << F.getName() << "\n";
+ provenSafe[&F] = 1;
+ //first check if all its parents are safe, i.e. all calling functions are safe
+ for (Value::use_iterator I = F.use_begin(), E = F.use_end(); I != E; ++I) {
+ User *U = *I;
+ if (CallInst *CI = dyn_cast<CallInst>(U)) {
+ Function *parentfunc = CI->getParent()->getParent();
+ // out << " Inside Check Safety Uses paren func " << getValueName(parentfunc) << " func " << getValueName(&F) << endl;
+ if (!(provenSafe.count(parentfunc))) { //may be wa have to change it to indicate the end
+ checkSafety(*parentfunc, out);
+ }
+ }
+ }
+ // we know that all its parents are safe.
+ // out << " Inside Check Safety " << getValueName(&F) << endl;
+ if (fMap[&F] != 0) {
+ MemAccessInstListType MemAccessInstList = fMap[&F]->getMemAccessInstList();
+ MemAccessInstListIt maI = MemAccessInstList.begin(), maE = MemAccessInstList.end();
+ for (; maI != maE; ++maI) {
+ ABCExprTree *root = fMap[&F]->getSafetyConstraint(*maI);
+ // out << " Inside Check Safety getting root for " << getValueName(&F) << endl;
+ ABCExprTree * argConstraints = getArgumentConstraints(F);
+ if (argConstraints) {
+ root = new ABCExprTree(root,argConstraints,"&&");
+ }
+ //omega stuff should go in here.
+ out << " P" <<count << " := {[i] : \n";
+ if (root != 0)root->print(out);
+ const Module *M = (*maI)->getParent()->getParent()->getParent();
+
+ printStandardArguments(M, out);
+
+ out << " && (argv = argc) ";
+ out << "};\n P"<<count++ << ";\n";
+ //gist something to prove safety
+ // out << " Inside Check Safety getting retval constr " << getValueName(&F) << endl;
+ }
+ }
+ }
+
+ bool ArrayBoundsCheck::run(Module &M) {
+ Table = new SlotCalculator(&M, true);
+ initialize();
+ /* printing preliminaries */
+ outputDeclsForOmega(M);
+ // out << "outputting decls for Omega done" <<endl;
+
+
+ // out << " First Collect Safety Constraints ";
+ for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ Function &F = *I;
+ if (!(F.hasName()) || (KnownFuncDB.find(F.getName()) == KnownFuncDB.end()))
+ collectSafetyConstraints(F);
+ }
+
+ // out << "Output of collect safety constraints \n";
+ for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ // out << " Function Name "<< getValueName(I) << "\n";
+ if (fMap[I] != 0) {
+ // we dont have info for external functions
+ MemAccessInstListType MemAccessInstList = fMap[I]->getMemAccessInstList();
+ MemAccessInstListIt maI = MemAccessInstList.begin(), maE = MemAccessInstList.end();
+ for (; maI != maE; ++maI) {
+ ABCExprTree *root = fMap[I]->getSafetyConstraint(*maI);
+ // root->print(out);
+ }
+ }
+ out << "\n";
+ }
+
+ // out << " Now checking the constraints \n ";
+ for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ if (!(provenSafe.count(I) != 0)) checkSafety(*I, out);
+ }
+ out << " NumAccessses" <<count << " := {[i] : i = " <<count<< " };\n";
+ // out << "done \n" ;
+ return false;
+ }
+
+
+ void ArrayBoundsCheck::collectSafetyConstraints(Function &F) {
+ if (fMap.count(&F) == 0) {
+ fMap[&F] = new FuncLocalInfo();
+ }
+
+ for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
+ Instruction *iLocal = *I;
+ if (isa<CastInst>(iLocal)) {
+ //This is an ugly hack for kill code to work
+ if (isa<GetElementPtrInst>(iLocal->getOperand(0))) {
+ iLocal = cast<Instruction>(iLocal->getOperand(0));
+ }
+ }
+ if (isa<GetElementPtrInst>(iLocal)) {
+ GetElementPtrInst *MAI = cast<GetElementPtrInst>(iLocal);
+ if (const PointerType *PT = dyn_cast<PointerType>(MAI->getPointerOperand()->getType())) {
+ if (!isa<StructType>(PT->getElementType())) {
+ User::op_iterator mI = MAI->op_begin(), mE = MAI->op_end();
+ if (mI == mE) {
+ continue;
+ }
+ mI++;
+ ABCExprTree *root;
+ string varName = getValueName(MAI->getPointerOperand());
+ if ((*mI)->getType() == Type::LongTy) {
+ LinearExpr *le = new LinearExpr(*mI,*Table);
+ Constraint* c1 = new Constraint(varName,le,"<="); // length < index
+ ABCExprTree* abctemp1 = new ABCExprTree(c1);
+ Constraint* c2 = new Constraint("0",le,">"); // 0 > index
+ ABCExprTree* abctemp2 = new ABCExprTree(c2);
+ root = new ABCExprTree(abctemp1, abctemp2, "||");
+ }
+ mI++;
+ for (; mI != mE; ++mI) {
+ if ((*mI)->getType() == Type::LongTy) {
+ LinearExpr *le = new LinearExpr(*mI,*Table);
+ varName = varName+"_i" ;
+ Constraint* c1 = new Constraint(varName,le,"<="); // length < index
+ ABCExprTree* abctemp1 = new ABCExprTree(c1);
+ Constraint* c2 = new Constraint("0",le,">"); // 0 > index
+ ABCExprTree* abctemp2 = new ABCExprTree(c2);
+ ABCExprTree*abctempor = new ABCExprTree(abctemp1,abctemp2,"||"); // abctemp1 || abctemp2
+ root = new ABCExprTree(root, abctempor, "||");
+ }
+ }
+ //reinitialize mI , now getting the constraints on the indices
+ //We need to clear DoneList since we are getting constraints for a new access.
+ DoneList.clear();
+ addControlDependentConditions(MAI->getParent(), &root);
+ mI = MAI->idx_begin();
+ for (; mI != mE; ++mI) {
+ if ((*mI)->getType() == Type::LongTy) {
+ getConstraints(*mI,&root);
+ }
+ }
+ getConstraints(MAI->getPointerOperand(),&root);
+ fMap[&F]->addSafetyConstraint(MAI,root);
+ fMap[&F]->addMemAccessInst(MAI);
+ }
+ }
+ }
+ }
+ }
+
+
+ void ArrayBoundsCheck::addBranchConstraints(BranchInst *BI,BasicBlock *Successor, ABCExprTree **rootp) {
+ //this has to be a conditional branch, otherwise we wouldnt have been here
+ assert((BI->isConditional()) && "abcd wrong pi node");
+ if (SetCondInst *SCI = dyn_cast<SetCondInst>(BI->getCondition())) {
+
+ //SCI now has the conditional statement
+ Value *operand0 = SCI->getOperand(0);
+ Value *operand1 = SCI->getOperand(1);
+
+ getConstraints(operand0,rootp);
+ getConstraints(operand1,rootp);
+
+
+ LinearExpr *l1 = new LinearExpr(operand1,*Table);
+
+ string var0 = getValueName(operand0);
+ Constraint *ct;
+
+ switch(SCI->getOpcode()) {
+ case Instruction::SetLE :
+ //there are 2 cases for each opcode!
+ //its the true branch or the false branch
+ if (BI->getSuccessor(0) == Successor) {
+ //true branch
+ ct = new Constraint(var0,l1,"<=");
+ } else {
+ ct = new Constraint(var0,l1,">");
+ }
+ break;
+ case Instruction::SetNE :
+ if (BI->getSuccessor(0) == Successor) {
+ //true branch
+ ct = new Constraint(var0,l1,"!=");
+ } else {
+ ct = new Constraint(var0,l1,"=");
+ }
+ break;
+ case Instruction::SetEQ :
+ if (BI->getSuccessor(0) == Successor) {
+ //true branch
+ ct = new Constraint(var0,l1,"=");
+ } else {
+ //false branch
+ ct = new Constraint(var0,l1,"!=");
+ }
+ break;
+ case Instruction::SetGE :
+ if (BI->getSuccessor(0) == Successor) {
+ //true branch
+ ct = new Constraint(var0,l1,">=");
+ } else {
+ //false branch
+ ct = new Constraint(var0,l1,"<");
+ }
+ break;
+ case Instruction::SetLT :
+ if (BI->getSuccessor(0) == Successor) {
+ //true branch
+ ct = new Constraint(var0,l1,"<");
+ } else {
+ //false branch
+ ct = new Constraint(var0,l1,">=");
+ }
+ break;
+ case Instruction::SetGT :
+ if (BI->getSuccessor(0) == Successor) {
+ //true branch
+ ct = new Constraint(var0,l1,">");
+ } else {
+ //false branch
+ ct = new Constraint(var0,l1,"<=");
+ }
+ break;
+ default :
+ break;
+ }
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(ct),"&&"); //
+ }
+ }
+
+
+
+ // SimplifyExpression: Analyze an expression inorder to simplify it
+
+
+ LinearExpr* ArrayBoundsCheck::SimplifyExpression( Value *Expr, ABCExprTree **rootp) {
+ assert(Expr != 0 && "Can't classify a null expression!");
+ if (Expr->getType() == Type::FloatTy || Expr->getType() == Type::DoubleTy)
+ return new LinearExpr(Expr, *Table) ; // nothing known return variable itself
+
+ switch (Expr->getValueType()) {
+ case Value::InstructionVal: break; // Instruction... hmmm... investigate.
+ case Value::TypeVal: case Value::BasicBlockVal:
+ case Value::FunctionVal:
+ out << "test\n ";
+ assert(1 && "Unexpected expression type to classify!");
+ // out << "Bizarre thing to expr classify: " << Expr << "\n";
+ out << "testing \n ";
+ return 0;
+ case Value::GlobalVariableVal: // Global Variable & Method argument:
+ case Value::ArgumentVal: // nothing known, return variable itself
+ return new LinearExpr(Expr, *Table);
+ case Value::ConstantVal: // Constant value, just return constant
+ Constant *CPV = cast<Constant>(Expr);
+ if (CPV->getType()->isIntegral()) { // It's an integral constant!
+ if (ConstantArray *CA = dyn_cast<ConstantArray>(CPV)) {
+ const std::vector<Use> &Values = CA->getValues();
+ ConstantInt *CPI = cast<ConstantInt>(Values[1]);
+ return new LinearExpr(CPI, *Table);
+ } else {
+ ConstantInt *CPI = cast<ConstantInt>(Expr);
+ return new LinearExpr(CPI, *Table);
+ }
+ }
+ return new LinearExpr(Expr, *Table); //nothing known, just return itself
+ }
+
+ Instruction *I = cast<Instruction>(Expr);
+ const Type *Ty = I->getType();
+
+ switch (I->getOpcode()) { // Handle each instruction type seperately
+ case Instruction::Add: {
+ LinearExpr* Left = (SimplifyExpression(I->getOperand(0), rootp));
+ if (Left == 0) {
+ Left = new LinearExpr(I->getOperand(0), *Table);
+ }
+ LinearExpr* Right = (SimplifyExpression(I->getOperand(1), rootp));
+ if (Right == 0) {
+ Right = new LinearExpr(I->getOperand(1), *Table);
+ }
+ Left->addLinearExpr(Right);
+ return Left;
+ }
+ case Instruction::Sub: {
+ LinearExpr* Left = (SimplifyExpression(I->getOperand(0), rootp));
+ if (Left == 0) {
+ Left = new LinearExpr(I->getOperand(0), *Table);
+ }
+ LinearExpr* Right = (SimplifyExpression(I->getOperand(1), rootp));
+ if (Right == 0) {
+ Right = new LinearExpr(I->getOperand(1), *Table);
+ }
+ Right->negate();
+ Left->addLinearExpr(Right);
+ return Left;
+ }
+ case Instruction::SetLE :
+ case Instruction::SetNE :
+ case Instruction::SetEQ :
+ case Instruction::SetGE :
+ case Instruction::SetLT :
+ case Instruction::SetGT : {
+ LinearExpr* L = new LinearExpr(I->getOperand(1),*Table);
+ return L;
+ };
+ case Instruction::Mul :
+
+ LinearExpr* Left = (SimplifyExpression(I->getOperand(0),rootp));
+ if (Left == 0) {
+ Left = new LinearExpr(I->getOperand(0), *Table);
+ }
+ LinearExpr* Right = (SimplifyExpression(I->getOperand(1),rootp));
+ if (Right == 0) {
+ Right = new LinearExpr(I->getOperand(1), *Table);
+ }
+ return Left->mulLinearExpr(Right);
+ } // end switch
+ if (isa<CastInst>(I)) {
+ // out << "dealing with cast instruction ";
+ //FIXME .. this should be for all types not just sbyte
+ const Type *opType = I->getOperand(0)->getType();
+ if ((opType->isPrimitiveType()) && ((opType->getPrimitiveID() == Type::SByteTyID) || (opType->getPrimitiveID() == Type::UByteTyID))) {
+ string number = "255";
+ string number2 = "0";
+ string var = getValueName(I);
+ LinearExpr *l1 = new LinearExpr(I,*Table);
+ Constraint *c1 = new Constraint(number,l1,">=");
+ Constraint *c2 = new Constraint(number2,l1,"<=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c1),"&&");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c2),"&&");
+ Constraint *c = new Constraint(var, SimplifyExpression(I->getOperand(0),rootp),"=");
+ *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ return l1;
+ } else {
+ //special case for casts to beginning of structs
+ // the case is (sbyte*) (Struct with the first element arrauy)
+ //If it is a cast from struct to something else * ...
+ if (const PointerType *pType = dyn_cast<PointerType>(I->getType())){
+ const Type *eltype = pType->getElementType();
+ if (eltype->isPrimitiveType() && (eltype->getPrimitiveID() == Type::SByteTyID)) {
+ if (const PointerType *opPType = dyn_cast<PointerType>(opType)){
+ const Type *opEltype = opPType->getElementType();
+ if (const StructType *stype = dyn_cast<StructType>(opEltype)) {
+ if (const ArrayType *aType = dyn_cast<ArrayType>(stype->getContainedType(0))) {
+ if (aType->getElementType()->isPrimitiveType()) {
+ int elSize = aType->getNumElements();
+ switch (aType->getElementType()->getPrimitiveID()) {
+ case Type::ShortTyID :
+ case Type::UShortTyID : elSize *= 2; break;
+ case Type::IntTyID :
+ case Type::UIntTyID : elSize *= 4; break;
+ case Type::LongTyID :
+ case Type::ULongTyID : elSize *= 8; break;
+ default : break;
+ }
+ string varName = getValueName(I);
+ const Type* csiType = Type::getPrimitiveType(Type::IntTyID);
+ const ConstantSInt * signedOne = ConstantSInt::get(csiType,elSize);
+ LinearExpr *l1 = new LinearExpr(signedOne, *Table);
+ return l1;
+ // Constraint *c = new Constraint(varName, new LinearExpr(signedOne, *Table),"=");
+ // *rootp = new ABCExprTree(*rootp,new ABCExprTree(c),"&&");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return SimplifyExpression(I->getOperand(0),rootp);
+ } else {
+ getConstraints(I,rootp);
+ LinearExpr* ret = new LinearExpr(I,*Table);
+ return ret;
+ }
+ // Otherwise, I don't know anything about this value!
+ return 0;
+ }
+ RegisterOpt<ArrayBoundsCheck> X("abc",
+ "Array Bounds Checking pass");
+}
+
+Pass *createArrayBoundsCheckPass() { return new ABC::ArrayBoundsCheck(); }
diff --git a/safecode/lib/ArrayBoundChecks/Makefile b/safecode/lib/ArrayBoundChecks/Makefile
new file mode 100755
index 0000000..6096358
--- /dev/null
+++ b/safecode/lib/ArrayBoundChecks/Makefile
@@ -0,0 +1,9 @@
+
+LEVEL = ../../
+
+LIBRARYNAME = arrayboundcheck
+
+SHARED_LIBRARY = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/safecode/lib/Makefile b/safecode/lib/Makefile
new file mode 100755
index 0000000..f9dcaef
--- /dev/null
+++ b/safecode/lib/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ..
+
+PARALLEL_DIRS = ArrayBoundChecks PointerChecks
+
+include $(LEVEL)/Makefile.common
+
diff --git a/safecode/lib/PointerChecks/CZero.cpp b/safecode/lib/PointerChecks/CZero.cpp
new file mode 100755
index 0000000..13735d5
--- /dev/null
+++ b/safecode/lib/PointerChecks/CZero.cpp
@@ -0,0 +1,465 @@
+//===-- CZero.cpp - CZero security checks ----------------===//
+//
+// This transformation ensures that the code emitted (if there are no warnings)
+// poses no security threat to the target system.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO.h"
+#include "CZeroInfo.h"
+#include "llvm/Module.h"
+#include "llvm/Argument.h"
+#include "llvm/Constants.h"
+#include "llvm/iTerminators.h"
+#include "llvm/DerivedTypes.h"
+#include "Support/DepthFirstIterator.h"
+#include "llvm/Function.h"
+#include "llvm/Support/CFG.h"
+
+
+
+//===----------------------------------------------------------------------===//
+// CZeroInfo Implementation
+//===----------------------------------------------------------------------===//
+
+string CZeroInfo::WarningString(enum WarningType WT) {
+ switch (WT) {
+ case NoWarning: return "";
+ case IllegalMemoryLoc: return "Accessing an illegal memory location\n";
+ case UninitPointer: return "Potential use of location pointed to by uninitialized pointer variable\n";
+ default: return "";
+ }
+}
+
+string& CZeroInfo::getWarnings() {
+
+ // Lazy evaluation.
+ // TODO: Introduce an analyzed bool flag so that we
+ // don't end up redo-ing the evaluation when there are no security warnings
+ if (WarningsList != "")
+ return WarningsList;
+
+ // Uninitialized pointers
+ depthFirstGatherer();
+
+ findSpuriousInsts();
+
+ return WarningsList;
+
+}
+
+void CZeroInfo::depthFirstGatherer() {
+ // Adding the pointer values among the arguments to the alias graph
+ // We treat them as pointers to global targets.
+ const FunctionType *FT = cast<FunctionType>(TheFunction.getFunctionType());
+
+ for (Function::const_aiterator I = TheFunction.abegin(),
+ E = TheFunction.aend(); I != E; ++I) {
+ if (I->getType()->getPrimitiveID() == Type::PointerTyID)
+ PointerAliasGraph.addEdge(I, PointsToTarget::GlobalTarget);
+ }
+
+ df_iterator<const Function*> It = df_begin(&TheFunction), End = df_end(&TheFunction);
+ for ( ; It != End; It++) {
+ const BasicBlock *BB = *It;
+
+ // Look for store instructions sequentially in the basic block
+ // updating pointer alias graphs for the other instructions
+ BasicBlock::const_iterator iterBB;
+ for (iterBB = BB->begin(); iterBB != BB->end(); ++iterBB) {
+ const Instruction& I = *iterBB;
+
+ // NOTE!!! Removed the if (I) clause here
+ //
+ if (I.hasName() &&
+ I.getType()->getPrimitiveID() == Type::PointerTyID) {
+ // Each of these cases needs to modify the alias graph appropriately
+ if (isa<AllocaInst>(I)) {
+ PointerAliasGraph.addEdge(&I, &I);
+ }
+ else if (isa<MallocInst>(I)) {
+ // TODO: We'll be making this illegal and only allowing
+ // calls to rmalloc and rfree.
+ PointerAliasGraph.addEdge(&I, &I);
+ }
+ else if (isa<LoadInst>(I)) {
+ PointerAliasGraph.addEdge(&I, PointsToTarget::DummyTarget);
+ }
+ else if (isa<GetElementPtrInst>(I)) {
+ // Check if the operand is a global value, in which case we
+ // generate an alias to a generic global value.
+ if (!isa<ConstantPointerNull>(I.getOperand(0)))
+ if (isa<GlobalValue>(I.getOperand(0)) ||
+ isa<Constant>(I.getOperand(0)))
+ PointerAliasGraph.addEdge(&I, PointsToTarget::GlobalTarget);
+ else
+ PointerAliasGraph.addAlias(&I, I.getOperand(0));
+ else
+ PointerAliasGraph.addEdge(&I, PointsToTarget::DummyTarget);
+ }
+ else if (isa<PHINode>(I)) {
+ PointerAliasGraph.addEdge(&I, &I);
+ }
+ else if (isa<CallInst>(I)) {
+ PointerAliasGraph.addEdge(&I, PointsToTarget::GlobalTarget);
+ }
+ else if (isa<CastInst>(I)) {
+ PointerAliasGraph.addEdge(&I, PointsToTarget::DummyTarget);
+ }
+ }
+ else if (!I.hasName()) {
+ if (isa<StoreInst>(I)) {
+ // We only consider stores of scalar pointers.
+ if (I.getNumOperands() <= 2 ||
+ (I.getNumOperands() == 3 &&
+ I.getOperand(2) != ConstantUInt::get(Type::UIntTy, 0))) {
+ if (!isa<ConstantPointerNull>(I.getOperand(1))) {
+ BBPointerLiveInfo[BB][I.getOperand(1)] = true;
+ df_iterator<const Function*> localIt = df_begin(&TheFunction),
+ localEnd = df_end(&TheFunction);
+ for ( ; localIt != localEnd; ++localIt) {
+ if (DomSet->dominates((BasicBlock *) BB,
+ (BasicBlock *) *localIt))
+ BBPointerLiveInfo[*localIt][I.getOperand(1)] = true;
+ }
+ } else {
+ WarningsList += "Stores to null pointers disallowed in CZero\n";
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bool CZeroInfo::checkPredecessors(const BasicBlock *BB, const Value *V,
+ set<const BasicBlock *>& visitedBlocks) {
+ set<const Value *> aliases = PointerAliasGraph.getAliases(V);
+ set<const Value *>::iterator Siter;
+
+ // Check the block BB itself. Necessary when checkPredecessors is called
+ // for a PHINode pointer
+ for (Siter = aliases.begin(); Siter != aliases.end(); ++Siter)
+ if (BBPointerLiveInfo[BB][*Siter])
+ return true;
+
+ pred_const_iterator PI = pred_begin(BB), PEnd = pred_end(BB);
+
+ if (PI != PEnd) {
+ for (; PI != PEnd; ++PI) {
+ if (visitedBlocks.find(*PI) == visitedBlocks.end()) {
+ bool alivehere = false;
+ visitedBlocks.insert(*PI);
+ for (Siter = aliases.begin(); Siter != aliases.end(); ++Siter)
+ if (BBPointerLiveInfo[*PI][*Siter])
+ alivehere = true;
+ if (!alivehere) {
+ if (!checkPredecessors(*PI, V, visitedBlocks))
+ return false;
+ else {
+ // Caching the value for future use.
+ for (Siter = aliases.begin(); Siter != aliases.end(); Siter++)
+ BBPointerLiveInfo[*PI][*Siter] = true;
+ }
+ }
+ }
+ }
+ }
+ else
+ return false;
+ return true;
+}
+
+// if BigSet contains even one of the elements in the smallset, return true
+// else return false
+static bool setContains (set<const Value *> BigSet, set<const Value *> SmallSet) {
+ set<const Value *>::iterator Siter;
+ bool found = false;
+ if (!SmallSet.empty())
+ for (Siter = SmallSet.begin(); Siter != SmallSet.end() && !found; Siter++)
+ if (BigSet.find(*Siter) != BigSet.end())
+ found = true;
+ return found;
+}
+
+// Called on PointerVar only if PointerVar is a scalar, non-heap variable.
+// However the case that PointerVar points to a phi node needs to be handled.
+enum WarningType CZeroInfo::checkIfStored(const BasicBlock *BB,
+ const Value *PointerVar,
+ std::set<const Value *>&
+ LocalStoresSoFar) {
+ if (!isa<ConstantPointerNull>(PointerVar))
+ return NoWarning;
+ // TODO: Optimization if a pointer is defined in the same basic block.
+ set<const Value *> aliases = PointerAliasGraph.getAliases(PointerVar);
+ set<const BasicBlock *> visitedBlocks;
+ visitedBlocks.insert(BB);
+ if (PointerAliasGraph.getPointsToInfo(PointerVar).isPHINode()) {
+ // We have a phi node pointer
+ // Solve separate problems for each of the predecessors
+ if (!setContains(LocalStoresSoFar, aliases)) {
+ // Each of the predecessor branches.
+ bool stored = true;
+ const PHINode *pI = dyn_cast<const PHINode>(PointerAliasGraph.getPointsToInfo(PointerVar).val());
+ // There has to be at least one predecessor
+ for (unsigned int i = 0; i < pI->getNumIncomingValues(); i++) {
+ if (!checkPredecessors(pI->getIncomingBlock(i),
+ pI->getIncomingValue(i),
+ visitedBlocks))
+ stored = false;
+ }
+ if (!stored)
+ return UninitPointer;
+ else {
+ // Cache the value
+ set<const Value *>::iterator Siter;
+ for (Siter = aliases.begin(); Siter != aliases.end(); Siter++)
+ BBPointerLiveInfo[BB][*Siter] = true;
+ }
+ }
+ }
+ else {
+ if (!setContains(LocalStoresSoFar, aliases))
+ if (!checkPredecessors(BB, PointerVar, visitedBlocks))
+ return UninitPointer;
+ else {
+ // Cache the information that PointerVar and its aliases are live here
+ set<const Value *>::iterator Siter;
+ for (Siter = aliases.begin(); Siter != aliases.end(); Siter++)
+ BBPointerLiveInfo[BB][*Siter] = true;
+ }
+ }
+ return NoWarning;
+}
+
+// Called for load and getelementptr instructions
+enum WarningType CZeroInfo::checkInstruction(const BasicBlock *BB,
+ const Instruction *I,
+ std::set<const Value *>&
+ LocalStoresSoFar) {
+ const Value *PointerVar = I->getOperand(0);
+ if (isa<ConstantPointerNull>(I->getOperand(0)))
+ return IllegalMemoryLoc;
+
+ // Check for pointer arithmetic
+ if (!PointerAliasGraph.getPointsToInfo(PointerVar).isArray()) {
+ if (I->getNumOperands() > 1) {
+ // Check that every operand is 0 except for struct accesses.
+ const Type *elemType = I->getType();
+ for(unsigned int i = 1; i < I->getNumOperands(); i++) {
+ if (elemType->getPrimitiveID() == Type::PointerTyID) {
+ if (I->getOperand(i) != ConstantUInt::get(Type::UIntTy, 0))
+ return IllegalMemoryLoc;
+ elemType = cast<const PointerType>(elemType)->getElementType();
+ }
+ else if (elemType->getPrimitiveID() == Type::ArrayTyID) {
+ elemType = cast<const ArrayType>(elemType)->getElementType();
+ }
+ else if (elemType->getPrimitiveID() == Type::StructTyID) {
+ elemType = cast<const StructType>(elemType)->getTypeAtIndex(I->getOperand(i));
+ }
+ }
+ }
+ if (!isa<GlobalValue>(PointerVar) &&
+ !(PointerAliasGraph.getPointsToInfo(PointerVar).isGlobal()) &&
+ !(PointerAliasGraph.getPointsToInfo(PointerVar).isHeap()) &&
+ !(PointerAliasGraph.getPointsToInfo(PointerVar).isStruct()) &&
+ !(PointerAliasGraph.getPointsToInfo(PointerVar).isDummy())) {
+ return checkIfStored(BB, PointerVar, LocalStoresSoFar);
+ }
+ }
+
+ return NoWarning;
+}
+
+bool CZeroInfo::findSpuriousInsts() {
+ bool WarningFlag = false;
+ df_iterator<const Function*> It = df_begin(&TheFunction), End = df_end(&TheFunction);
+ for ( ; It != End; It++) {
+ const BasicBlock *BB = *It;
+ std::set<const Value *> LocalStoresSoFar;
+
+ // Sequentially scan instructions in the block
+ BasicBlock::const_iterator iterBB;
+ for (iterBB = BB->begin(); iterBB != BB->end(); iterBB++) {
+ const Instruction *I = iterBB;
+ enum WarningType WT;
+ if (!I)
+ continue;
+
+ if (isa<CastInst>(I)) {
+ // Disallow cast instructions involving pointers
+ if (I->getType()->getPrimitiveID() == Type::PointerTyID) {
+ WarningsList += I->getName() + ": Casts to pointers disallowed" +
+ "in CZero\n";
+ WarningFlag = true;
+ }
+ else if (I->getOperand(0)->getType()->getPrimitiveID()
+ == Type::PointerTyID) {
+ WarningsList += I->getName() + ":Casts from a pointer disallowed " +
+ "in CZero\n";
+ WarningFlag = true;
+ }
+ }
+ // If this is a store instruction update LocalStoresSoFar
+ else if (isa<StoreInst>(I)) {
+ LocalStoresSoFar.insert(I->getOperand(1));
+
+ // Check that there is no pointer arithmetic here
+ if (!PointerAliasGraph.getPointsToInfo(I->getOperand(1)).isArray()) {
+ const Type *elemType = I->getOperand(1)->getType();
+ for(unsigned int i = 2; i < I->getNumOperands(); i++) {
+ if (elemType->getPrimitiveID() == Type::PointerTyID) {
+ if (I->getOperand(i) != ConstantUInt::get(Type::UIntTy, 0)) {
+ WarningsList += "Stores to pointer variables should not have pointer arithmetic\n";
+ WarningFlag = true;
+ }
+ elemType = cast<const PointerType>(elemType)->getElementType();
+ }
+ else if (elemType->getPrimitiveID() == Type::ArrayTyID) {
+ elemType = cast<const ArrayType>(elemType)->getElementType();
+ }
+ else if (elemType->getPrimitiveID() == Type::StructTyID) {
+ elemType = cast<const StructType>(elemType)->getTypeAtIndex(I->getOperand(i));
+ }
+ }
+ }
+
+ // If a pointer is stored to another pointer, then we check that
+ // the pointer being stored has been stored to. (boy thats twisted!)
+ if (I->getOperand(0)->getType()->getPrimitiveID() ==
+ Type::PointerTyID) {
+ if (!isa<GlobalValue>(I->getOperand(0)) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(0)).isGlobal()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(0)).isHeap()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(0)).isStruct()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(0)).isDummy()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(0)).isArray())) {
+ // TODO: Array
+ WT = checkIfStored(BB, I->getOperand(0), LocalStoresSoFar);
+ if (WT == UninitPointer)
+ WarningsList += "Pointer value being stored potentially uninitialized\n";
+ else
+ WarningsList += WarningString(WT);
+ if (WT != NoWarning)
+ WarningFlag = true;
+ }
+ }
+
+ }
+ else if (isa<LoadInst>(I)) {
+ // Check for globals, heaps and structs... all of which we ignore.
+ WT = checkInstruction(BB, I, LocalStoresSoFar);
+ if (WT == IllegalMemoryLoc) {
+ WarningsList += "Load from illegal memory location\n";
+ WarningFlag = true;
+ }
+ else {
+ WarningsList += WarningString(WT);
+ if (WT != NoWarning)
+ WarningFlag = true;
+ }
+ }
+ else if (isa<GetElementPtrInst>(I)) {
+ WT = checkInstruction(BB, I, LocalStoresSoFar);
+ // don't check for pointer arithmetic any more
+ if (WT == IllegalMemoryLoc) {
+ // WarningsList += "Pointer Arithmetic disallowed\n";
+ // WarningFlag = true;
+ }
+ else {
+ WarningsList += WarningString(WT);
+ if (WT != NoWarning)
+ WarningFlag = true;
+ }
+ }
+ else if (isa<CallInst>(I)) {
+ if (I->getNumOperands() > 1)
+ for (unsigned int i = 1; i < I->getNumOperands(); i++) {
+ if (I->getOperand(i)->getType()->getPrimitiveID() ==
+ Type::PointerTyID) {
+ if (!isa<GlobalValue>(I->getOperand(i)) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(i)).isGlobal()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(i)).isHeap()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(i)).isStruct()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(i)).isDummy()) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(i)).isArray())) {
+ WT = checkIfStored(BB, I->getOperand(i), LocalStoresSoFar);
+ if (WT == UninitPointer)
+ WarningsList += "Pointer value argument to function call potentially uninitialized \n";
+ else
+ WarningsList += WarningString(WT);
+ if (WT != NoWarning)
+ WarningFlag = true;
+ }
+ }
+ }
+ }
+ else if (isa<ReturnInst>(I)) {
+ if (I->getNumOperands() > 0)
+ if (I->getOperand(0)->getType()->getPrimitiveID() ==
+ Type::PointerTyID) {
+ if (!isa<GlobalValue>(I->getOperand(0)) &&
+ !(PointerAliasGraph.getPointsToInfo
+ (I->getOperand(0)).isGlobal())) {
+ WarningsList += "Pointer value being returned by function does not point to a global value (only intra-procedural region analysis done)\n";
+ WarningFlag = true;
+ }
+ }
+ }
+ }
+ }
+ return WarningFlag;
+}
+
+namespace {
+
+ // The Pass class we implement
+ struct CZeroPtrChecks : public FunctionPass {
+
+ const char *getPassName() const { return "CZero security pass"; }
+
+ virtual bool runOnFunction (Function &F) {
+ bool Error = false;
+ DominatorSet *DomSet = &getAnalysis<DominatorSet>();
+ CZeroInfo *CZI = new CZeroInfo(F, DomSet);
+ std::cerr << "\nIn function " << F.getName() << "\n";
+ if (CZI->getWarnings() != "") {
+ std::cerr << "Security Warning/s: \n";
+ std::cerr << CZI->getWarnings();
+ Error = true;
+ }
+
+ free(CZI);
+
+ return false;
+
+ }
+
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ // TODO: Check when we generate code.
+ AU.setPreservesAll();
+ AU.addRequired<DominatorSet>();
+ }
+
+ };
+
+ RegisterOpt<CZeroPtrChecks> X("czeroptrchecks", "CZero Pointer Checks");
+
+}
+
+//Externally visible
+
+Pass *createCZeroUninitPtrPass() {
+ return new CZeroPtrChecks();
+}
diff --git a/safecode/lib/PointerChecks/CZeroInfo.h b/safecode/lib/PointerChecks/CZeroInfo.h
new file mode 100755
index 0000000..948b2f8
--- /dev/null
+++ b/safecode/lib/PointerChecks/CZeroInfo.h
@@ -0,0 +1,264 @@
+//===- llvm/Analysis/CZeroInfo.h - CZero info --------*- C++ -*--=//
+//
+// This file checks the LLVM code for any potential security holes. We allow
+// a restricted number of usages in order to preserve memory safety etc.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LLVM_ANALYSIS_CZEROINFO_H
+#define LLVM_ANALYSIS_CZEROINFO_H
+
+#include "llvm/Type.h"
+#include "llvm/Value.h"
+#include "llvm/iMemory.h"
+#include "llvm/iPHINode.h"
+#include "llvm/iOther.h"
+#include "llvm/BasicBlock.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/SlotCalculator.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CFG.h"
+#include <algorithm>
+using std::string;
+using std::map;
+using std::vector;
+using std::set;
+
+
+// A dummy node is used when the value pointed to is unknown as yet.
+struct PointsToTarget {
+private:
+ const Value *Val;
+ bool Dummy;
+ bool Global;
+
+ // If the node is a dummy, the following fields don't matter
+ bool Array;
+ bool Struct;
+ bool Heap;
+ int TargetID;
+
+ static int NextTargetID;
+
+public:
+
+ static const int DummyTarget = 1;
+ static const int GlobalTarget = 2;
+
+ bool operator<(const PointsToTarget PTT) const {
+ return (TargetID < PTT.TargetID);
+ }
+
+ PointsToTarget(const Value *V) : Val(V) {
+ TargetID = NextTargetID++;
+ Dummy = false;
+ Global = false;
+ Heap = false;
+ Array = false;
+ Struct = false;
+ if (isa<AllocaInst>(V)) {
+ const AllocaInst *AIV = dyn_cast<AllocaInst>(V);
+ Array = AIV->isArrayAllocation();
+ if (!AIV->isArrayAllocation()) {
+ if (AIV->getAllocatedType()->getPrimitiveID() == Type::StructTyID)
+ Struct = true;
+ }
+ }
+ else if (isa<MallocInst>(V)) {
+ const MallocInst *MIV = dyn_cast<MallocInst>(V);
+ Array = MIV->isArrayAllocation();
+ if (!MIV->isArrayAllocation()) {
+ if (MIV->getAllocatedType()->getPrimitiveID() == Type::StructTyID)
+ Struct = true;
+ }
+ Heap = true;
+ }
+ }
+
+ // Default constructor creates a dummy node.
+ PointsToTarget(int TargetType) {
+ TargetID = NextTargetID++;
+ Val = 0;
+ Dummy = false;
+ Global = false;
+ if (TargetType == DummyTarget) {
+ Dummy = true;
+ }
+ else if (TargetType == GlobalTarget) {
+ Global = true;
+ }
+ Struct = false;
+ Array = false;
+ Heap = false;
+ }
+
+ PointsToTarget() {
+ Val = 0;
+ Dummy = false;
+ Global = false;
+ Struct = false;
+ Array = false;
+ Heap = false;
+ }
+
+ bool isDummy() { return Dummy; }
+
+ bool isGlobal() { return Global; }
+
+ bool isArray() { return Array; }
+
+ bool isStruct() { return Struct; }
+
+ bool isHeap() { return Heap; }
+
+ bool isPHINode() {
+ if (Val)
+ return isa<PHINode>(Val);
+ else
+ return false;
+ }
+
+ const Value* val() { return Val; }
+
+};
+
+int PointsToTarget::NextTargetID = 0;
+
+// The graph is to be recreated for each function. This is done by each
+// CZeroInfo object being associated with a CZeroAliasGraph
+class CZeroAliasGraph {
+ // We ensure that memory locations on stack alone are initialized before
+ // use. A memory location on the stack is identified by the alloca
+ // instruction that created it.
+
+protected:
+ // There are edges from a SSA pointer variable to memory locations
+ // and from SSA pointer variables to phi nodes.
+ // Phi nodes are treated specially in the alias graph.
+ std::map<const Value *, PointsToTarget> pointsTo;
+
+ // Given a memory location, all the SSA pointer vars that point to it.
+ std::map<PointsToTarget, set<const Value *> > pointedBy;
+
+ // NOTE: every update to the graph should update both of these maps
+
+public:
+
+ // Add and edge from V1 to V2.
+ // Situations in which this happens is
+ // V1: SSA pointer variable, V2: alloca
+ // V1: SSA pointer variable, V2: phi node.
+ // Called only once for each SSA pointer value.
+ void addEdge (const Value *V1, const Value *V2) {
+ assert (pointsTo.count(V1) == 0 && "Value should not be inserted in graph yet");
+ PointsToTarget PT(V2);
+ pointsTo[V1] = PT;
+ pointedBy[PT].insert(V1);
+ }
+
+ // Add an edge from an SSA pointer variable to a dummy if we don't really
+ // know what it points to.
+ // Eg. If we load an int* from an int** since we currently don't do any
+ // flow-sensitive pointer tracking.
+ // This or addEdge(V1, V2) called only once for an SSA pointer value
+ void addEdge (const Value *V, int TargetType) {
+ assert (pointsTo.count(V) == 0 && "Value should not be inserted in graph yet");
+ PointsToTarget PT(TargetType);
+ pointsTo[V] = PT;
+ pointedBy[PT].insert(V);
+ }
+
+ PointsToTarget getPointsToInfo(const Value *V) {
+ return pointsTo[V];
+ }
+
+ set<const Value *> getPointedByInfo(PointsToTarget PT) {
+ return pointedBy[PT];
+ }
+
+ // make alias an alias of orig.
+ // If orig does not exist, then both of them need to point to a dummy node.
+ // NOTE: Call only when alias is the lvalue of an instruction.
+ // Call only once for a particular alias
+ void addAlias (const Value *alias, const Value *orig) {
+ assert (pointsTo.count(alias) == 0 && "Value alias not already in graph");
+ assert (pointsTo.count(orig) != 0 && "Value orig not inserted in graph yet");
+ if (pointsTo[orig].val())
+ addEdge(alias, pointsTo[orig].val());
+ else if (pointsTo[orig].isGlobal())
+ addEdge(alias, PointsToTarget::GlobalTarget);
+ else if (pointsTo[orig].isDummy())
+ addEdge(alias, PointsToTarget::DummyTarget);
+ }
+
+ // Returns aliases of the value.
+ // Return value also contains V
+ set<const Value *> getAliases(const Value *V) {
+ return pointedBy[pointsTo[V]];
+ }
+
+};
+
+
+enum WarningType {
+ NoWarning,
+ IllegalMemoryLoc,
+ UninitPointer
+};
+
+typedef std::map<const Value *, bool> LivePointerMap;
+
+// This class contains the information that CZero checks require.
+// This is re-instantiated and initialized for each function.
+class CZeroInfo {
+ // The two phases of our algorithm
+ // Phase 1: Examine all the stores by looking at basic blocks in a depth
+ // first manner and update the PointerLiveInfo map.
+ void depthFirstGatherer();
+ // Phase 2: Iterate through basic blocks depth first and see if the loads
+ // are safe i.e. there is a store of the pointer at every path to the load
+ // in question.
+ bool findSpuriousInsts();
+ bool checkPredecessors(const BasicBlock *BB, const Value *V,
+ set<const BasicBlock *>& vistedBlocks);
+ enum WarningType checkIfStored(const BasicBlock *BB,
+ const Value *V,
+ std::set<const Value *>& LocalStoresSoFar);
+
+ enum WarningType checkInstruction(const BasicBlock *BB,
+ const Instruction *I,
+ std::set<const Value *>& LocalStoresSoFar);
+
+ string WarningString(enum WarningType WT);
+
+protected:
+ const Function& TheFunction;
+
+ // This is the map (BasicBlock1 * Pointer variable) -> BasicBlock2
+ // where BasicBlock2 dominates BasicBlock1 and has a store to the pointer
+ std::map<const BasicBlock *, LivePointerMap> BBPointerLiveInfo;
+
+ // Alias graph to be used in the findSpuriousLoads phase
+ // Created in phase 1.
+ CZeroAliasGraph PointerAliasGraph;
+
+ // Dominator set information
+ DominatorSet *DomSet;
+
+ string WarningsList;
+
+
+public:
+
+ CZeroInfo (Function& F, DominatorSet* DSet) : TheFunction(F), DomSet(DSet) {
+
+ }
+
+ // Public access method to get all the warnings associated with
+ // the particular function.
+ string& getWarnings ();
+};
+
+#endif
+
diff --git a/safecode/lib/PointerChecks/CheckStackPointer.cpp b/safecode/lib/PointerChecks/CheckStackPointer.cpp
new file mode 100755
index 0000000..367df37
--- /dev/null
+++ b/safecode/lib/PointerChecks/CheckStackPointer.cpp
@@ -0,0 +1,92 @@
+//===-- StackSafety.cpp - Analysis for ensuring stack safety ------------//
+// Implementation of StackSafety.h
+//
+
+
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/Instruction.h"
+#include "llvm/iTerminators.h"
+#include "llvm/BasicBlock.h"
+#include "llvm/Type.h"
+#include "llvm/Pass.h"
+#include "llvm/Analysis/DataStructure.h"
+#include "llvm/Analysis/DSGraph.h"
+#include "llvm/Analysis/DSNode.h"
+#include "llvm/Support/InstIterator.h"
+
+namespace {
+ struct checkStackSafety : public Pass {
+ public :
+ const char *getPassName() const { return "Stack Safety Check";}
+ virtual bool run(Module &M);
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<TDDataStructures>();
+ }
+ private :
+ bool checkIfReachesAlloca(DSNode *DSN);
+ };
+ RegisterOpt<checkStackSafety> css("css1",
+ "check stack safety");
+}
+
+
+bool checkStackSafety::checkIfReachesAlloca(DSNode *DSN) {
+ if (DSN->NodeType & DSNode::AllocaNode) {
+ return true;
+ }
+ for (unsigned i = 0, e = DSN->getSize(); i < e; i += DS::PointerSize)
+ if (DSNode *DSNchild = DSN->getLink(i).getNode()) {
+ if (checkIfReachesAlloca(DSNchild)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool checkStackSafety::run(Module &M) {
+
+ TDDataStructures *TDDS;
+ TDDS = &getAnalysis<TDDataStructures>();
+
+ for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
+ Function &F = *MI;
+
+ if (!F.isExternal()) {
+ DSGraph &TDG = TDDS->getDSGraph(F);
+
+ // check if return value is a pointers
+ if (isa<PointerType>(F.getReturnType())) {
+ //return value type is a pointer
+ for(inst_iterator ii = inst_begin(F), ie = inst_end(&F); ii != ie; ++ii) {
+ if (ReturnInst *RI = dyn_cast<ReturnInst>(*ii)) {
+ DSNode *DSN = TDG.getNodeForValue(RI).getNode();
+ if (checkIfReachesAlloca(DSN)) {
+ std::cerr << "Instruction : \n" << RI << "points to a stack location\n";
+ std::cerr << "In Function " << F.getName() << "\n";
+ return false;
+ }
+ }
+ }
+ }
+ Function::aiterator AI = F.abegin(), AE = F.aend();
+ for (; AI != AE; ++AI) {
+ if (isa<PointerType>(AI->getType())) {
+ DSNode *DSN = TDG.getNodeForValue(AI).getNode();
+ if (checkIfReachesAlloca(DSN)) {
+ std::cerr << "Instruction : \n" << AI << "points to a stack location\n";
+ std::cerr << "In Function " << F.getName() << "\n";
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+
+Pass *createStackSafetyPass() { return new checkStackSafety(); }
+
+
+
diff --git a/safecode/lib/PointerChecks/FreeRemoval.cpp b/safecode/lib/PointerChecks/FreeRemoval.cpp
new file mode 100755
index 0000000..02d8c7c
--- /dev/null
+++ b/safecode/lib/PointerChecks/FreeRemoval.cpp
@@ -0,0 +1,379 @@
+//===-- FreeRemoval.cpp - EmbeC transformation that removes frees ------------//
+// Implementation of FreeRemoval.h : an EmbeC pass
+//
+// Some assumptions:
+// * Correctness of pool allocation
+// * Destroys at end of functions.
+// Pool pointer aliasing assumptions
+// -pool pointer copies via gep's are removed
+// -no phinode takes two pool pointers because then they would be the same pool
+// Result: If we look at pool pointer defs and look for their uses... we check
+// that their only uses are calls to pool_allocs, pool_frees and pool_destroys.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Transforms/IPO.h"
+#include "Support/PostOrderIterator.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/iOther.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Analysis/CallGraph.h"
+#include "llvm/Transforms/PoolAllocate.h"
+#include "Support/VectorExtras.h"
+#include <set>
+#include <map>
+#include <string>
+using std::set;
+using std::map;
+
+
+namespace {
+
+ struct EmbeCFreeRemoval : public Pass {
+
+ // The function representing 'poolmakeunfreeable'
+ Function *PoolMakeUnfreeable;
+
+ bool run(Module &M);
+
+ static const std::string PoolI;
+ static const std::string PoolA;
+ static const std::string PoolArr;
+ static const std::string PoolF;
+ static const std::string PoolD;
+
+ void checkPoolSSAVarUses(Function *F, Value *V,
+ map<Value *, set<Instruction *> > &FuncAllocs,
+ map<Value *, set<Instruction *> > &FuncFrees,
+ map<Value *, set<Instruction *> > &FuncDestroy);
+
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ // TODO: Check!
+ AU.setPreservesAll();
+ AU.addRequired<PoolAllocate>();
+ AU.addRequired<CallGraph>();
+ }
+
+ private:
+
+ Module *CurModule;
+
+ bool moduleChanged;
+ bool hasError;
+
+ // The following maps are only for pool pointers that escape a function.
+ // Associates function with set of pools that are freed or alloc'ed using
+ // pool_free or pool_alloc but not destroyed within the function.
+ // These have to be pool pointer arguments to the function
+ map<Function *, set<Value *> > FuncFreedPools;
+ map<Function *, set<Value *> > FuncAllocedPools;
+ map<Function *, set<Value *> > FuncDestroyedPools;
+
+ };
+
+ const std::string EmbeCFreeRemoval::PoolI = "poolinit";
+ const std::string EmbeCFreeRemoval::PoolA = "poolalloc";
+ const std::string EmbeCFreeRemoval::PoolArr = "poolallocarray";
+ const std::string EmbeCFreeRemoval::PoolF = "poolfree";
+ const std::string EmbeCFreeRemoval::PoolD = "pooldestroy";
+
+ RegisterOpt<EmbeCFreeRemoval> Y("EmbeC", "EmbeC pass that removes all frees and issues warnings if behaviour has changed");
+
+}
+
+
+// Check if SSA pool pointer variable V has uses other than alloc, free and
+// destroy
+void EmbeCFreeRemoval::checkPoolSSAVarUses(Function *F, Value *V,
+ map<Value *, set<Instruction *> > &FuncPoolAllocs,
+ map<Value *, set<Instruction *> > &FuncPoolFrees,
+ map<Value *, set<Instruction *> > &FuncPoolDestroys) {
+ if (V->use_begin() != V->use_end()) {
+ for (Value::use_iterator UI = V->use_begin(), UE = V->use_end();
+ UI != UE; ++UI) {
+ // Check that the use is nothing except a call to pool_alloc, pool_free
+ // or pool_destroy
+ if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
+ if (Function *calledF = dyn_cast<Function>(CI->getOperand(0))) {
+ if (!calledF->isExternal()) {
+ // the pool pointer is passed to the called function
+
+ // Find the formal parameter corresponding to the parameter V
+ int operandNo;
+ for (unsigned int i = 1; i < CI->getNumOperands(); i++)
+ if (CI->getOperand(i) == V)
+ operandNo = i;
+
+ Value *formalParam;
+ int opi = 0;
+ for (Function::aiterator I = calledF->abegin(),
+ E = calledF->aend();
+ I != E && opi <= operandNo; ++I, ++opi)
+ if (opi == operandNo)
+ formalParam = I;
+
+ // if the called function has undestroyed frees in pool formalParam
+ if (FuncFreedPools[calledF].find(formalParam) !=
+ FuncFreedPools[calledF].end() &&
+ FuncDestroyedPools[calledF].find(formalParam) ==
+ FuncDestroyedPools[calledF].end()) {
+ FuncPoolFrees[V].insert(cast<Instruction>(*UI));
+ }
+ // if the called function has undestroyed allocs in formalParam
+ if (FuncAllocedPools[calledF].find(formalParam) !=
+ FuncAllocedPools[calledF].end()) {
+ FuncPoolAllocs[V].insert(cast<Instruction>(*UI));
+ }
+
+ // if the called function has a destroy in formalParam
+ if (FuncDestroyedPools[calledF].find(formalParam) !=
+ FuncDestroyedPools[calledF].end()) {
+ FuncPoolDestroys[V].insert(cast<Instruction>(*UI));
+ }
+ } else {
+ // external function
+ if (calledF->getName() == EmbeCFreeRemoval::PoolI) {
+ // Insert call to poolmakeunfreeable after every poolinit since
+ // we do not free memory to the system for safety in all cases.
+ // Also, insert prototype in the module
+
+ // NB: This has to be in sync with the types in PoolAllocate.cpp
+ const Type *VoidPtrTy = PointerType::get(Type::SByteTy);
+ // The type to allocate for a pool descriptor: { sbyte*, uint }
+ const Type *PoolDescType =
+ StructType::get(make_vector<const Type*>(VoidPtrTy,
+ Type::UIntTy, 0));
+ const PointerType *PoolDescPtr = PointerType::get(PoolDescType);
+ std::vector<const Type*> PMUArgs(1, PoolDescPtr);
+ FunctionType *PoolMakeUnfreeableTy =
+ FunctionType::get(Type::VoidTy, PMUArgs, false);
+ PoolMakeUnfreeable = CurModule->getOrInsertFunction("poolmakeunfreeable", PoolMakeUnfreeableTy);
+ new CallInst(PoolMakeUnfreeable, make_vector(V), "",
+ CI->getNext());
+ std::cerr << "here\n";
+ assert(0);
+ moduleChanged = true;
+ } else if (calledF->getName() == EmbeCFreeRemoval::PoolA ||
+ calledF->getName() == EmbeCFreeRemoval::PoolArr) {
+ FuncPoolAllocs[V].insert(cast<Instruction>(*UI));
+ } else if (calledF->getName() == EmbeCFreeRemoval::PoolF) {
+ FuncPoolFrees[V].insert(cast<Instruction>(*UI));
+ } else if (calledF->getName() == EmbeCFreeRemoval::PoolD) {
+ FuncPoolDestroys[V].insert(cast<Instruction>(*UI));
+ } else {
+ hasError = true;
+ std::cerr << "EmbeC: " << F->getName() << ": Unrecognized pool variable use \n";
+ }
+ }
+ } else {
+ // indirect function call
+ hasError = true;
+ std::cerr << "EmbeC: " << F->getName() << ": Unrecognized pool variable use \n";
+ }
+ } else {
+ hasError = true;
+ std::cerr << "EmbeC: " << F->getName() << ": Unrecognized pool variable use \n";
+ }
+ }
+ }
+}
+
+// Returns true if BB1 follows BB2 in some path in F
+static bool followsBlock(BasicBlock *BB1, BasicBlock *BB2, Function *F,
+ set<BasicBlock *> visitedBlocks) {
+ if (succ_begin(BB2) != succ_end(BB2)) {
+ for (BasicBlock::succ_iterator BBSI = succ_begin(BB2), BBSE =
+ succ_end(BB2); BBSI != BBSE; ++BBSI) {
+ if (visitedBlocks.find(*BBSI) == visitedBlocks.end())
+ if (*BBSI == BB1)
+ return true;
+ else {
+ visitedBlocks.insert(*BBSI);
+ if (followsBlock(BB1, *BBSI, F, visitedBlocks))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Checks if Inst1 follows Inst2 in any path in the function F.
+static bool followsInst(Instruction *Inst1, Instruction *Inst2, Function *F) {
+ if (Inst1->getParent() == Inst2->getParent()) {
+ for (BasicBlock::iterator BBI = Inst2, BBE = Inst2->getParent()->end();
+ BBI != BBE; ++BBI)
+ if (Inst1 == &(*BBI))
+ return true;
+ }
+ set<BasicBlock *> visitedBlocks;
+ return followsBlock(Inst1->getParent(), Inst2->getParent(), F,
+ visitedBlocks);
+}
+
+
+bool EmbeCFreeRemoval::run(Module &M) {
+ CurModule = &M;
+ moduleChanged = false;
+ hasError = false;
+
+ Function *mainF = M.getMainFunction();
+
+ if (!mainF) {
+ hasError = true;
+ std::cerr << "EmbeC: Function main required\n";
+ return false;
+ }
+
+ // Bottom up on the call graph
+ // TODO: Take care of recursion/mutual recursion
+ CallGraph &CG = getAnalysis<CallGraph>();
+ PoolAllocate &PoolInfo = getAnalysis<PoolAllocate>();
+
+
+ for (po_iterator<CallGraph*> CGI = po_begin(&CG),
+ CGE = po_end(&CG); CGI != CGE; ++CGI) {
+
+ Function *F = (*CGI)->getFunction();
+
+ // Ignore nodes representing external functions in the call graph
+ if (!F)
+ continue;
+
+ // All its pool SSA variables including its arguments
+ set<Value *> FuncPoolPtrs;
+
+ // Pool SSA variables that are used in allocs, destroy and free or calls
+ // to functions that escaped allocs, destroys and frees respectively.
+ map<Value *, set<Instruction *> > FuncPoolAllocs, FuncPoolFrees,
+ FuncPoolDestroys;
+
+ // Traverse the function finding poolfrees and calls to functions that
+ // have poolfrees without pooldestroys on all paths in that function.
+
+ if (!F->isExternal()) {
+ // For each pool pointer def check its uses and ensure that there are
+ // no uses other than the pool_alloc, pool_free or pool_destroy calls
+
+
+ PA::FuncInfo* PAFI = 0;
+
+ // Calculating the FuncInfo for F
+ for (Module::iterator ModI = CurModule->begin(), ModE = CurModule->end();
+ ModI != ModE;
+ ++ModI) {
+ PA::FuncInfo* PFI = PoolInfo.getFuncInfo(*ModI);
+ if (PFI) {
+ if (&*ModI == F || (PFI->Clone && PFI->Clone == F)) {
+ PAFI = PFI;
+ break;
+ }
+ }
+ }
+
+
+ // If the function has no pool pointers (args or SSA), ignore the
+ // function.
+ if (!PAFI)
+ continue;
+
+ if (!PAFI->PoolDescriptors.empty()) {
+ for (map<DSNode*, Value*>::iterator PAFII =
+ PAFI->PoolDescriptors.begin(),
+ PAFIE = PAFI->PoolDescriptors.end(); PAFII != PAFIE; ++PAFII) {
+ checkPoolSSAVarUses(F, (*PAFII).second, FuncPoolAllocs,
+ FuncPoolFrees, FuncPoolDestroys);
+ FuncPoolPtrs.insert((*PAFII).second);
+ }
+ }
+ else
+ continue;
+
+ // Do a local analysis on these and update the pool variables that escape
+ // the function (poolfrees without pooldestroys, poolallocs)
+ // For each instruction in the list of free/calls to free, do
+ // the following: go down to the bottom of the function looking for
+ // allocs till you see destroy. If you don't see destroy on some path,
+ // update escape list.
+ // Update escape list with allocs without destroys too for arguments
+ // As well as arguments that are destroyed.
+ // TODO: Modify implementation so you are not checking that there is no
+ // alloc to other pools follows a free in the function, but to see that
+ // there is a destroy on pool between a free and an alloc to another pool
+ // Current Assumption: destroys are at the end of a function.
+ if (!FuncPoolFrees.empty()) {
+ for (map<Value *, set<Instruction *> >::iterator ValueI =
+ FuncPoolFrees.begin(), ValueE = FuncPoolFrees.end();
+ ValueI != ValueE; ++ValueI) {
+ if (!(*ValueI).second.empty()) {
+ for (set<Instruction *>::iterator FreeInstI =
+ (*ValueI).second.begin(),
+ FreeInstE = (*ValueI).second.end();
+ FreeInstI != FreeInstE; ++FreeInstI) {
+ // For each free instruction or call to a function which escapes
+ // a free in pool (*ValueI).first
+ for (set<Value *>::iterator PoolPtrsI = FuncPoolPtrs.begin(),
+ PoolPtrsE = FuncPoolPtrs.end(); PoolPtrsI != PoolPtrsE;
+ ++PoolPtrsI) {
+ // For each pool pointer other than the one in the free
+ // instruction under consideration, check that allocs to it
+ // don't follow the free on any path.
+ if (*PoolPtrsI != (*ValueI).first) {
+ map<Value *, set<Instruction *> >::iterator AllocSet=
+ FuncPoolAllocs.find(*PoolPtrsI);
+ if (AllocSet != FuncPoolAllocs.end())
+ for (set<Instruction *>::iterator AllocInstI =
+ (*AllocSet).second.begin(),
+ AllocInstE = (*AllocSet).second.end();
+ AllocInstI != AllocInstE; ++AllocInstI)
+ if (followsInst(*AllocInstI, *FreeInstI, F)) {
+ hasError = true;
+ std::cerr << "EmbeC: Free instruction could not be "
+ << "removed. Allocs from other pools "
+ << "following free instruction\n";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ // Assumption: if we have pool_destroy on a pool in a function, then it
+ // is on all exit paths of the function
+ // TODO: correct later.
+ // Therefore, all pool ptr arguments that have frees but no destroys
+ // escape the function. Similarly all pool ptr arguments that have
+ // allocs but no destroys escape the function
+
+ for (set<Value *>::iterator PoolPtrsI = FuncPoolPtrs.begin(),
+ PoolPtrsE = FuncPoolPtrs.end(); PoolPtrsI != PoolPtrsE;
+ ++PoolPtrsI) {
+ if (isa<Argument>(*PoolPtrsI)) {
+ // Only for pool pointers that are arguments
+ if (FuncPoolFrees.find(*PoolPtrsI) != FuncPoolFrees.end())
+ FuncFreedPools[F].insert(*PoolPtrsI);
+ if (FuncPoolAllocs.find(*PoolPtrsI) != FuncPoolAllocs.end())
+ FuncAllocedPools[F].insert(*PoolPtrsI);
+ if (FuncPoolDestroys.find(*PoolPtrsI) != FuncPoolDestroys.end()) {
+ FuncDestroyedPools[F].insert(*PoolPtrsI);
+ }
+ }
+ }
+
+ // TODO
+ // For each function, check that the frees in the function are safe i.e.
+ // there are no mallocs between the free and its corresponding
+ // pool_destroy and then remove the pool free call.
+ }
+ }
+
+ return moduleChanged;
+
+}
+
+Pass *createEmbeCFreeRemovalPass() { return new EmbeCFreeRemoval(); }
+
+
+
diff --git a/safecode/lib/PointerChecks/Makefile b/safecode/lib/PointerChecks/Makefile
new file mode 100755
index 0000000..ee41085
--- /dev/null
+++ b/safecode/lib/PointerChecks/Makefile
@@ -0,0 +1,7 @@
+LEVEL = ../../
+LIBRARYNAME = pointerchecks
+
+BUILD_ARCHIVE = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/safecode/tools/EmbeC/Makefile b/safecode/tools/EmbeC/Makefile
new file mode 100755
index 0000000..1b905e8
--- /dev/null
+++ b/safecode/tools/EmbeC/Makefile
@@ -0,0 +1,9 @@
+LEVEL = ../..
+TOOLNAME = embec
+LLVMLIBS = bcreader bcwriter instrument \
+ profpaths scalaropts \
+ ipo ipa.a datastructure.a transforms target.a analysis \
+ transformutils vmcore support cwriter
+USEDLIBS = pointerchecks arrayboundcheck
+TOOLLINKOPTS = -ldl
+include $(LEVEL)/Makefile.common
diff --git a/safecode/tools/EmbeC/embec.cpp b/safecode/tools/EmbeC/embec.cpp
new file mode 100755
index 0000000..cca459f
--- /dev/null
+++ b/safecode/tools/EmbeC/embec.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+// LLVM 'embec' UTILITY : Checks codes for safety as per the EmbeC language
+// rules. Targetted at embedded systems.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Bytecode/Reader.h"
+#include "llvm/Assembly/CWriter.h"
+#include "UninitPointer.h"
+#include "SafeDynMemAlloc.h"
+#include "ArrayBoundsCheck.h"
+#include "StackSafety.h"
+#include "llvm/Transforms/Scalar.h"
+#include "Support/CommandLine.h"
+#include "Support/Signals.h"
+#include <fstream>
+#include <memory>
+using namespace std;
+
+static cl::opt<string>
+InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));
+
+static cl::opt<string>
+OutputFilename("o", cl::desc("Override output filename"),
+ cl::value_desc("filename"));
+
+static cl::opt<bool>
+Force("f", cl::desc("Overwrite output files"));
+
+int main(int argc, char **argv) {
+
+ cl::ParseCommandLineOptions(argc, argv,
+ " llvm .bc -> .bc modular optimizer\n");
+
+ // Load the input module...
+ std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
+
+
+ if (M.get() == 0) {
+ cerr << "bytecode didn't read correctly.\n";
+ return 1;
+ }
+
+ // Figure out what stream we are supposed to write to...
+
+ std::ostream *Out = &std::cout; // Default to printing to stdout...
+
+
+ if (OutputFilename != "") {
+ Out = new std::ofstream(OutputFilename.c_str());
+
+
+ if (!Out->good()) {
+ cerr << "Error opening " << OutputFilename << "!\n";
+ return 1;
+ }
+
+ }
+
+
+ //
+ PassManager Passes;
+
+ //Add passes
+ Passes.add(createCZeroUninitPtrPass());
+ Passes.add(createABCPreProcessPass());
+ Passes.add(createArrayBoundsCheckPass());
+ Passes.add(createStackSafetyPass());
+ Passes.add(createEmbeCFreeRemovalPass());
+
+ // Now that we have all of the passes ready, run them.
+ if (Passes.run(*M.get()))
+ cerr << "Program modified.\n";
+ (*Out) << M.get();
+ // WriteToC(M.get(), *Out, false);
+
+ return 0;
+}
diff --git a/safecode/tools/Makefile b/safecode/tools/Makefile
new file mode 100755
index 0000000..4c799f9
--- /dev/null
+++ b/safecode/tools/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ..
+PARALLEL_DIRS = Parse EmbeC
+
+include $(LEVEL)/Makefile.common
+
diff --git a/safecode/tools/Parse/Makefile b/safecode/tools/Parse/Makefile
new file mode 100755
index 0000000..aa12097
--- /dev/null
+++ b/safecode/tools/Parse/Makefile
@@ -0,0 +1,9 @@
+LEVEL = ../..
+TOOLNAME = parse
+LLVMLIBS = bcreader bcwriter instrument profpaths scalaropts \
+ ipo ipa.a datastructure.a transforms target.a analysis \
+ transformutils vmcore support cwriter
+USEDLIBS = arrayboundcheck
+TOOLLINKOPTS = -ldl
+include $(LEVEL)/Makefile.common
+
diff --git a/safecode/tools/Parse/parse.cpp b/safecode/tools/Parse/parse.cpp
new file mode 100755
index 0000000..99708dc
--- /dev/null
+++ b/safecode/tools/Parse/parse.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+// LLVM 'czero' UTILITY
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Bytecode/Reader.h"
+#include "llvm/Assembly/CWriter.h"
+#include "ArrayBoundsCheck.h"
+#include "llvm/Transforms/Scalar.h"
+#include "Support/CommandLine.h"
+#include "Support/Signals.h"
+#include <fstream>
+#include <memory>
+using namespace std;
+
+static cl::opt<string>
+InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));
+
+static cl::opt<string>
+OutputFilename("o", cl::desc("Override output filename"),
+ cl::value_desc("filename"));
+
+static cl::opt<bool>
+Force("f", cl::desc("Overwrite output files"));
+
+int main(int argc, char **argv) {
+
+ cl::ParseCommandLineOptions(argc, argv,
+ " llvm .bc -> .bc modular optimizer\n");
+
+// Load the input module...
+ std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
+
+
+ if (M.get() == 0) {
+ cerr << "bytecode didn't read correctly.\n";
+ return 1;
+ }
+
+ // Figure out what stream we are supposed to write to...
+
+ std::ostream *Out = &std::cout; // Default to printing to stdout...
+
+
+ if (OutputFilename != "") {
+ Out = new std::ofstream(OutputFilename.c_str());
+
+ if (!Out->good()) {
+ cerr << "Error opening " << OutputFilename << "!\n";
+ return 1;
+ }
+
+ }
+
+
+ //
+ PassManager Passes;
+
+ //Add passes
+ Passes.add(createABCPreProcessPass());
+ // Passes.add(createPiNodeInsertionPass());
+ Passes.add(createArrayBoundsCheckPass());
+
+ // Now that we have all of the passes ready, run them.
+ Passes.run(*M.get());
+ (*Out) << M.get();
+ // WriteToC(M.get(), *Out, false);
+
+ return 0;
+}