klee
ExecutionState.cpp
Go to the documentation of this file.
1//===-- ExecutionState.cpp ------------------------------------------------===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ExecutionState.h"
11
12#include "Memory.h"
13
14#include "klee/Expr/Expr.h"
15#include "klee/Module/Cell.h"
18#include "klee/Module/KModule.h"
21
22#include "llvm/IR/Function.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/raw_ostream.h"
25
26#include <cassert>
27#include <iomanip>
28#include <map>
29#include <set>
30#include <sstream>
31#include <stdarg.h>
32
33using namespace llvm;
34using namespace klee;
35
36namespace {
37cl::opt<bool> DebugLogStateMerge(
38 "debug-log-state-merge", cl::init(false),
39 cl::desc("Debug information for underlying state merging (default=false)"),
40 cl::cat(MergeCat));
41}
42
43/***/
44
45std::uint32_t ExecutionState::nextID = 1;
46
47/***/
48
49StackFrame::StackFrame(KInstIterator _caller, KFunction *_kf)
50 : caller(_caller), kf(_kf), callPathNode(0),
51 minDistToUncoveredOnReturn(0), varargs(0) {
52 locals = new Cell[kf->numRegisters];
53}
54
56 : caller(s.caller),
57 kf(s.kf),
58 callPathNode(s.callPathNode),
59 allocas(s.allocas),
60 minDistToUncoveredOnReturn(s.minDistToUncoveredOnReturn),
61 varargs(s.varargs) {
62 locals = new Cell[s.kf->numRegisters];
63 for (unsigned i=0; i<s.kf->numRegisters; i++)
64 locals[i] = s.locals[i];
65}
66
68 delete[] locals;
69}
70
71/***/
72
74 : pc(kf->instructions), prevPC(pc) {
75 pushFrame(nullptr, kf);
76 setID();
77}
78
80 for (const auto &cur_mergehandler: openMergeStack){
81 cur_mergehandler->removeOpenState(this);
82 }
83
84 while (!stack.empty()) popFrame();
85}
86
88 pc(state.pc),
89 prevPC(state.prevPC),
90 stack(state.stack),
91 incomingBBIndex(state.incomingBBIndex),
92 depth(state.depth),
93 addressSpace(state.addressSpace),
94 constraints(state.constraints),
95 pathOS(state.pathOS),
96 symPathOS(state.symPathOS),
97 coveredLines(state.coveredLines),
98 symbolics(state.symbolics),
99 cexPreferences(state.cexPreferences),
100 arrayNames(state.arrayNames),
101 openMergeStack(state.openMergeStack),
102 steppedInstructions(state.steppedInstructions),
103 instsSinceCovNew(state.instsSinceCovNew),
104 unwindingInformation(state.unwindingInformation
105 ? state.unwindingInformation->clone()
106 : nullptr),
107 coveredNew(state.coveredNew),
108 forkDisabled(state.forkDisabled) {
109 for (const auto &cur_mergehandler: openMergeStack)
110 cur_mergehandler->addOpenState(this);
111}
112
114 depth++;
115
116 auto *falseState = new ExecutionState(*this);
117 falseState->setID();
118 falseState->coveredNew = false;
119 falseState->coveredLines.clear();
120
121 return falseState;
122}
123
125 stack.emplace_back(StackFrame(caller, kf));
126}
127
129 const StackFrame &sf = stack.back();
130 for (const auto * memoryObject : sf.allocas)
131 addressSpace.unbindObject(memoryObject);
132 stack.pop_back();
133}
134
135void ExecutionState::addSymbolic(const MemoryObject *mo, const Array *array) {
136 symbolics.emplace_back(ref<const MemoryObject>(mo), array);
137}
138
139
140
141llvm::raw_ostream &klee::operator<<(llvm::raw_ostream &os, const MemoryMap &mm) {
142 os << "{";
143 MemoryMap::iterator it = mm.begin();
144 MemoryMap::iterator ie = mm.end();
145 if (it!=ie) {
146 os << "MO" << it->first->id << ":" << it->second.get();
147 for (++it; it!=ie; ++it)
148 os << ", MO" << it->first->id << ":" << it->second.get();
149 }
150 os << "}";
151 return os;
152}
153
155 if (DebugLogStateMerge)
156 llvm::errs() << "-- attempting merge of A:" << this << " with B:" << &b
157 << "--\n";
158 if (pc != b.pc)
159 return false;
160
161 // XXX is it even possible for these to differ? does it matter? probably
162 // implies difference in object states?
163
164 if (symbolics != b.symbolics)
165 return false;
166
167 {
168 std::vector<StackFrame>::const_iterator itA = stack.begin();
169 std::vector<StackFrame>::const_iterator itB = b.stack.begin();
170 while (itA!=stack.end() && itB!=b.stack.end()) {
171 // XXX vaargs?
172 if (itA->caller!=itB->caller || itA->kf!=itB->kf)
173 return false;
174 ++itA;
175 ++itB;
176 }
177 if (itA!=stack.end() || itB!=b.stack.end())
178 return false;
179 }
180
181 std::set< ref<Expr> > aConstraints(constraints.begin(), constraints.end());
182 std::set< ref<Expr> > bConstraints(b.constraints.begin(),
183 b.constraints.end());
184 std::set< ref<Expr> > commonConstraints, aSuffix, bSuffix;
185 std::set_intersection(aConstraints.begin(), aConstraints.end(),
186 bConstraints.begin(), bConstraints.end(),
187 std::inserter(commonConstraints, commonConstraints.begin()));
188 std::set_difference(aConstraints.begin(), aConstraints.end(),
189 commonConstraints.begin(), commonConstraints.end(),
190 std::inserter(aSuffix, aSuffix.end()));
191 std::set_difference(bConstraints.begin(), bConstraints.end(),
192 commonConstraints.begin(), commonConstraints.end(),
193 std::inserter(bSuffix, bSuffix.end()));
194 if (DebugLogStateMerge) {
195 llvm::errs() << "\tconstraint prefix: [";
196 for (std::set<ref<Expr> >::iterator it = commonConstraints.begin(),
197 ie = commonConstraints.end();
198 it != ie; ++it)
199 llvm::errs() << *it << ", ";
200 llvm::errs() << "]\n";
201 llvm::errs() << "\tA suffix: [";
202 for (std::set<ref<Expr> >::iterator it = aSuffix.begin(),
203 ie = aSuffix.end();
204 it != ie; ++it)
205 llvm::errs() << *it << ", ";
206 llvm::errs() << "]\n";
207 llvm::errs() << "\tB suffix: [";
208 for (std::set<ref<Expr> >::iterator it = bSuffix.begin(),
209 ie = bSuffix.end();
210 it != ie; ++it)
211 llvm::errs() << *it << ", ";
212 llvm::errs() << "]\n";
213 }
214
215 // We cannot merge if addresses would resolve differently in the
216 // states. This means:
217 //
218 // 1. Any objects created since the branch in either object must
219 // have been free'd.
220 //
221 // 2. We cannot have free'd any pre-existing object in one state
222 // and not the other
223
224 if (DebugLogStateMerge) {
225 llvm::errs() << "\tchecking object states\n";
226 llvm::errs() << "A: " << addressSpace.objects << "\n";
227 llvm::errs() << "B: " << b.addressSpace.objects << "\n";
228 }
229
230 std::set<const MemoryObject*> mutated;
235 for (; ai!=ae && bi!=be; ++ai, ++bi) {
236 if (ai->first != bi->first) {
237 if (DebugLogStateMerge) {
238 if (ai->first < bi->first) {
239 llvm::errs() << "\t\tB misses binding for: " << ai->first->id << "\n";
240 } else {
241 llvm::errs() << "\t\tA misses binding for: " << bi->first->id << "\n";
242 }
243 }
244 return false;
245 }
246 if (ai->second.get() != bi->second.get()) {
247 if (DebugLogStateMerge)
248 llvm::errs() << "\t\tmutated: " << ai->first->id << "\n";
249 mutated.insert(ai->first);
250 }
251 }
252 if (ai!=ae || bi!=be) {
253 if (DebugLogStateMerge)
254 llvm::errs() << "\t\tmappings differ\n";
255 return false;
256 }
257
258 // merge stack
259
262 for (std::set< ref<Expr> >::iterator it = aSuffix.begin(),
263 ie = aSuffix.end(); it != ie; ++it)
264 inA = AndExpr::create(inA, *it);
265 for (std::set< ref<Expr> >::iterator it = bSuffix.begin(),
266 ie = bSuffix.end(); it != ie; ++it)
267 inB = AndExpr::create(inB, *it);
268
269 // XXX should we have a preference as to which predicate to use?
270 // it seems like it can make a difference, even though logically
271 // they must contradict each other and so inA => !inB
272
273 std::vector<StackFrame>::iterator itA = stack.begin();
274 std::vector<StackFrame>::const_iterator itB = b.stack.begin();
275 for (; itA!=stack.end(); ++itA, ++itB) {
276 StackFrame &af = *itA;
277 const StackFrame &bf = *itB;
278 for (unsigned i=0; i<af.kf->numRegisters; i++) {
279 ref<Expr> &av = af.locals[i].value;
280 const ref<Expr> &bv = bf.locals[i].value;
281 if (!av || !bv) {
282 // if one is null then by implication (we are at same pc)
283 // we cannot reuse this local, so just ignore
284 } else {
285 av = SelectExpr::create(inA, av, bv);
286 }
287 }
288 }
289
290 for (std::set<const MemoryObject*>::iterator it = mutated.begin(),
291 ie = mutated.end(); it != ie; ++it) {
292 const MemoryObject *mo = *it;
293 const ObjectState *os = addressSpace.findObject(mo);
294 const ObjectState *otherOS = b.addressSpace.findObject(mo);
295 assert(os && !os->readOnly &&
296 "objects mutated but not writable in merging state");
297 assert(otherOS);
298
300 for (unsigned i=0; i<mo->size; i++) {
301 ref<Expr> av = wos->read8(i);
302 ref<Expr> bv = otherOS->read8(i);
303 wos->write(i, SelectExpr::create(inA, av, bv));
304 }
305 }
306
308
310 for (const auto &constraint : commonConstraints)
311 m.addConstraint(constraint);
312 m.addConstraint(OrExpr::create(inA, inB));
313
314 return true;
315}
316
317void ExecutionState::dumpStack(llvm::raw_ostream &out) const {
318 unsigned idx = 0;
319 const KInstruction *target = prevPC;
320 for (ExecutionState::stack_ty::const_reverse_iterator
321 it = stack.rbegin(), ie = stack.rend();
322 it != ie; ++it) {
323 const StackFrame &sf = *it;
324 Function *f = sf.kf->function;
325 const InstructionInfo &ii = *target->info;
326 out << "\t#" << idx++;
327 std::stringstream AssStream;
328 AssStream << std::setw(8) << std::setfill('0') << ii.assemblyLine;
329 out << AssStream.str();
330 out << " in " << f->getName().str() << " (";
331 // Yawn, we could go up and print varargs if we wanted to.
332 unsigned index = 0;
333 for (Function::arg_iterator ai = f->arg_begin(), ae = f->arg_end();
334 ai != ae; ++ai) {
335 if (ai!=f->arg_begin()) out << ", ";
336
337 out << ai->getName().str();
338 // XXX should go through function
339 ref<Expr> value = sf.locals[sf.kf->getArgRegister(index++)].value;
340 if (isa_and_nonnull<ConstantExpr>(value))
341 out << "=" << value;
342 }
343 out << ")";
344 if (ii.file != "")
345 out << " at " << ii.file << ":" << ii.line;
346 out << "\n";
347 target = sf.caller;
348 }
349}
350
353 c.addConstraint(e);
354}
355
357 cexPreferences = cexPreferences.insert(cond);
358}
void unbindObject(const MemoryObject *mo)
Remove a binding from the address space.
const ObjectState * findObject(const MemoryObject *mo) const
Lookup a binding from a MemoryObject.
ObjectState * getWriteable(const MemoryObject *mo, const ObjectState *os)
Obtain an ObjectState suitable for writing.
static ref< ConstantExpr > alloc(const llvm::APInt &v)
Definition: Expr.h:1065
Manages constraints, e.g. optimisation.
Definition: Constraints.h:50
void addConstraint(const ref< Expr > &constraint)
constraint_iterator end() const
constraint_iterator begin() const
ExecutionState representing a path under exploration.
stack_ty stack
Stack representing the current instruction stream.
void addConstraint(ref< Expr > e)
void pushFrame(KInstIterator caller, KFunction *kf)
void addSymbolic(const MemoryObject *mo, const Array *array)
ConstraintSet constraints
Constraints collected so far.
std::vector< ref< MergeHandler > > openMergeStack
The objects handling the klee_open_merge calls this state ran through.
bool merge(const ExecutionState &b)
AddressSpace addressSpace
Address space used by this state (e.g. Global and Heap)
std::vector< std::pair< ref< const MemoryObject >, const Array * > > symbolics
Ordered list of symbolics: used to generate test cases.
void dumpStack(llvm::raw_ostream &out) const
void addCexPreference(const ref< Expr > &cond)
ExecutionState(const ExecutionState &state)
KInstIterator prevPC
Pointer to instruction which is currently executed.
std::uint32_t depth
Exploration depth, i.e., number of times KLEE branched for this state.
ExecutionState * branch()
ImmutableSet< ref< Expr > > cexPreferences
A set of boolean expressions the user has requested be true of a counterexample.
KInstIterator pc
Pointer to instruction to be executed after the current instruction.
static const Width Bool
Definition: Expr.h:100
iterator begin() const
Definition: ImmutableMap.h:83
iterator end() const
Definition: ImmutableMap.h:86
unsigned size
size in bytes
Definition: Memory.h:52
ref< Expr > read8(unsigned offset) const
Definition: Memory.cpp:364
void write(unsigned offset, ref< Expr > value)
Definition: Memory.cpp:506
static ref< Expr > create(ref< Expr > c, ref< Expr > t, ref< Expr > f)
Definition: Expr.cpp:592
Definition: Ref.h:82
Statistic instructions
Definition: main.cpp:291
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const MemoryMap &mm)
llvm::cl::OptionCategory MergeCat
ref< Expr > value
Definition: Cell.h:19
InstructionInfo stores debug information for a KInstruction.
const std::string & file
Source file name.
unsigned assemblyLine
Line number in generated assembly.ll.
unsigned line
Line number in source file.
unsigned getArgRegister(unsigned index)
Definition: KModule.h:63
llvm::Function * function
Definition: KModule.h:43
unsigned numRegisters
Definition: KModule.h:45
const InstructionInfo * info
Definition: KInstruction.h:35
std::vector< const MemoryObject * > allocas
StackFrame(KInstIterator caller, KFunction *kf)
KFunction * kf
KInstIterator caller