diff options
author | Martin Nowack <m.nowack@imperial.ac.uk> | 2018-07-07 00:00:33 +0100 |
---|---|---|
committer | Cristian Cadar <c.cadar@imperial.ac.uk> | 2019-03-19 10:01:55 +0000 |
commit | 28da6d9a03a7e2bf8ab1371267b049c73938c4e5 (patch) | |
tree | a90fce26299c741529b884573557051867a8f3ae | |
parent | 19640bf12f051ad531df7295674a574b43c242ae (diff) | |
download | klee-28da6d9a03a7e2bf8ab1371267b049c73938c4e5.tar.gz |
Fix representation of ReadExpr of equivalent arrays
ObjectStates can be shared between multiple states. A read expression of a symbolic object can be represented differently depending on previous read expression on the same object. If the read expression uses a symbolic index, all pending updates will become entries in the update list of the object state. If the same object state is read again, with a concrete index, the latest update list item will be referenced, even though it might contain more recent but non-essential updates. If, instead, a concrete read will be executed first, it does not contain the non-essential updates. For both executions, the ReadExpr with a constant index will have two different representations, which is not intented. This patch makes sure, we do not include more recent, non-essential updates for concrete reads. Fixes #921
-rw-r--r-- | lib/Expr/Expr.cpp | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp index 93b6c213..54f68f21 100644 --- a/lib/Expr/Expr.cpp +++ b/lib/Expr/Expr.cpp @@ -531,29 +531,30 @@ unsigned Array::computeHash() { /***/ ref<Expr> ReadExpr::create(const UpdateList &ul, ref<Expr> index) { - // rollback index when possible... - - // XXX this doesn't really belong here... there are basically two - // cases, one is rebuild, where we want to optimistically try various - // optimizations when the index has changed, and the other is - // initial creation, where we expect the ObjectState to have constructed - // a smart UpdateList so it is not worth rescanning. + // rollback update nodes if possible + // Iterate throught the update list from the most recent to the + // least reasent to find a potential written value for a concrete index; + // stop, if an update with symbolic has been found as we don't know which + // array element has been updated const UpdateNode *un = ul.head; bool updateListHasSymbolicWrites = false; for (; un; un=un->next) { + // Check if we have an equivalent concrete index ref<Expr> cond = EqExpr::create(index, un->index); - if (ConstantExpr *CE = dyn_cast<ConstantExpr>(cond)) { if (CE->isTrue()) + // Return the found value return un->value; } else { + // Found write with symbolic index updateListHasSymbolicWrites = true; break; } } if (ul.root->isConstantArray() && !updateListHasSymbolicWrites) { + // No updates with symbolic index to a constant array have been found if (ConstantExpr *CE = dyn_cast<ConstantExpr>(index)) { assert(CE->getWidth() <= 64 && "Index too large"); uint64_t concreteIndex = CE->getZExtValue(); @@ -564,6 +565,19 @@ ref<Expr> ReadExpr::create(const UpdateList &ul, ref<Expr> index) { } } + // Now, no update with this concrete index exists + // Try to remove any most recent but unimportant updates + if (ConstantExpr *CE = dyn_cast<ConstantExpr>(index)) { + assert(CE->getWidth() <= 64 && "Index too large"); + uint64_t concreteIndex = CE->getZExtValue(); + uint64_t size = ul.root->size; + if (concreteIndex < size) { + // Create shortened update list + UpdateList newUpdateList(ul.root, un); + return ReadExpr::alloc(newUpdateList, index); + } + } + return ReadExpr::alloc(ul, index); } |