AllocIdentify遍用于识别作为malloc及其他分配器包装器(wrapper)的函数。它派生自ModulePass。这意味着该遍以整个程序作为单元,以不可预测的次序访问函数体,添加或删除函数。
下面的allocators与deallocators是AllocIdentify用来保存内存分配器及回收器的名称的容器。它们的类型都是std::set<std::string>。
94 bool AllocIdentify::runOnModule(Module& M){
95
96 allocators.insert("malloc");
97 allocators.insert("calloc");
98 //allocators.insert("realloc");
99 //allocators.insert("memset");
100 deallocators.insert("free");
101 deallocators.insert("cfree");
102
103 bool changed;
104 do {
105 changed = false;
106 std::set<std::string> TempAllocators;
107 TempAllocators.insert( allocators.begin(),allocators.end());
108 std::set<std::string>::iterator it;
109 for(it =TempAllocators.begin(); it != TempAllocators.end(); ++it) {
110 Function* F = M.getFunction(*it);
111 if(!F)
112 continue;
113 for(Value::use_iteratorui = F->use_begin(), ue = F->use_end();
114 ui != ue; ++ui) {
115 // iteratethough all calls to malloc
116 if (CallInst* CI =dyn_cast<CallInst>(*ui)) {
117 // The functionthat calls malloc could be a potential allocator
118 Function *WrapperF =CI->getParent()->getParent();
119 if(WrapperF->doesNotReturn())
120 continue;
121 if(!(WrapperF->getReturnType()->isPointerTy()))
122 continue;
123 bool isWrapper = true;
124 for(Function::iterator BBI = WrapperF->begin(), E = WrapperF->end(); BBI !=E; ) {
125 BasicBlock &BB = *BBI++;
126
127 // Onlylook at return blocks.
128 ReturnInst *Ret =dyn_cast<ReturnInst>(BB.getTerminator());
129 if (Ret == 0) continue;
130
131 //checkfor ALL return values
132 if(flowsFrom(Ret, CI)) {
133 continue;
134 } else {
135 isWrapper = false;
136 break;
137 }
138 // iftrue for all return add to list of allocators
139 }
140 if(isWrapper)
141 isWrapper = isWrapper && isNotStored(CI);
142 if(isWrapper) {
143 changed =(allocators.find(WrapperF->getName()) == allocators.end());
144 if(changed) {
145 ++numAllocators;
146 allocators.insert(WrapperF->getName());
147 DEBUG(errs() <<WrapperF->getName().str() << "\n");
148 }
149 }
150 }
151 }
152 }
153 } while(changed);
110行的Module::getFunction在该模块中查找指定的函数,如果没有就返回null。如果模块中使用了内存分配器,在113行遍历这个函数的使用者,116行确保这个使用是一个函数调用。接下来119行与121行确保这个调用者返回一个指针。在124行我们遍历这个函数中的指令,对其中的ReturnInst调用下面的方法。
37 bool AllocIdentify::flowsFrom(Value *Dest,Value*Src) {
38 if(Dest == Src)
39 returntrue;
40 if(ReturnInst *Ret =dyn_cast<ReturnInst>(Dest)) {
41 returnflowsFrom(Ret->getReturnValue(), Src);
42 }
43 if(PHINode *PN =dyn_cast<PHINode>(Dest)) {
44 Function *F =PN->getParent()->getParent();
45 LoopInfo &LI = getAnalysis<LoopInfo>(*F);
46 // If this is aloop phi, ignore.
47 if(LI.isLoopHeader(PN->getParent()))
48 returnfalse;
49 bool ret = true;
50 for(unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
51 ret = ret &&flowsFrom(PN->getIncomingValue(i), Src);
52 }
53 return ret;
54 }
55 if(BitCastInst *BI =dyn_cast<BitCastInst>(Dest)) {
56 returnflowsFrom(BI->getOperand(0), Src);
57 }
58 if(isa<ConstantPointerNull>(Dest))
59 returntrue;
60 return false;
61 }
flowsFrom检查来自Src的值是否传播到Dest,在有限情形的递归后,使得flowsFrom返回true的条件只有38与58行。这是因为我们只检查简单的封装函数,它的返回值必须都是“return new …;”或者“return NULL;”以及“if (…){ p = new …; }else { p =NULL} return NULL;”这样的语句(包括额外的指针类型间的转换)。
除此之外,还要确保对分配函数调用的结果不会保存其他函数可以直接访问的地方(即不通过当前函数的返回值)。这就是isNotStored的作用。
63 bool isNotStored(Value *V) {
64 // check that Vis not stored to a location that is accessible outside this fn
65 for(Value::use_iteratorui = V->use_begin(), ue = V->use_end();
66 ui != ue; ++ui) {
67 if(isa<StoreInst>(*ui))
68 return false;
69 if(isa<ICmpInst>(*ui))
70 continue;
71 if(isa<ReturnInst>(*ui))
72 continue;
73 if(BitCastInst *BI =dyn_cast<BitCastInst>(*ui)) {
74 if(isNotStored(BI))
75 continue;
76 else
77 returnfalse;
78 }
79 if(PHINode *PN =dyn_cast<PHINode>(*ui)) {
80 if(isNotStored(PN))
81 continue;
82 else
83 returnfalse;
84 }
85
86 returnfalse;
87 }
88 return true;
89 }
如果上述条件都满足(142行),这是一个内存分配函数的封装函数,把它加入allocators,继续查找它的封装函数是否存在,直到没有发现这样的函数。
AllocIdentify::runOnModule(续)
155 do {
156 changed = false;
157 std::set<std::string>TempDeallocators;
158 TempDeallocators.insert(deallocators.begin(), deallocators.end());
159 std::set<std::string>::iterator it;
160 for(it =TempDeallocators.begin(); it != TempDeallocators.end(); ++it) {
161 Function* F = M.getFunction(*it);
162
163 if(!F)
164 continue;
165 for(Value::use_iteratorui = F->use_begin(), ue = F->use_end();
166 ui != ue; ++ui) {
167 // iteratethough all calls to malloc
168 if (CallInst* CI =dyn_cast<CallInst>(*ui)) {
169 // Thefunction that calls malloc could be a potential allocator
170 Function *WrapperF =CI->getParent()->getParent();
171
172 if(WrapperF->arg_size() != 1)
173 continue;
174 if(!WrapperF->arg_begin()->getType()->isPointerTy())
175 continue;
176 Argument *arg =dyn_cast<Argument>(WrapperF->arg_begin());
177 if(flowsFrom(CI->getOperand(1),arg)) {
178 changed =(deallocators.find(WrapperF->getName()) == deallocators.end());
179 if(changed) {
180 ++numDeallocators;
181 deallocators.insert(WrapperF->getName());
182 DEBUG(errs() <<WrapperF->getName().str() << "\n");
183 }
184 }
185 }
186 }
187 }
188 } while(changed);
189 return false;
190 }
对内存回收函数的处理也是非常类似的。runOnModule最后返回false,表示它没有改变这个模块对象。