aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/Expr
diff options
context:
space:
mode:
authorDan Liew <delcypher@gmail.com>2015-12-18 12:48:18 +0000
committerDan Liew <delcypher@gmail.com>2015-12-18 12:48:18 +0000
commit535be01be5ab33a0e7106e2d5511bba2797d1ed0 (patch)
tree026a4f1b16c1996755954f7824e0d10f8ed0ef8e /lib/Expr
parent7e75fa79b2e76251c2cd417a7eae8a7620b014ae (diff)
parent53ff7a002a8213a5d5e778bef2a895998d9890e1 (diff)
downloadklee-535be01be5ab33a0e7106e2d5511bba2797d1ed0.tar.gz
Merge pull request #315 from delcypher/array_leak
Try to fix leaking Array objects detected by ASan.
Diffstat (limited to 'lib/Expr')
-rw-r--r--lib/Expr/ArrayCache.cpp47
-rw-r--r--lib/Expr/Expr.cpp35
-rw-r--r--lib/Expr/Parser.cpp12
3 files changed, 55 insertions, 39 deletions
diff --git a/lib/Expr/ArrayCache.cpp b/lib/Expr/ArrayCache.cpp
new file mode 100644
index 00000000..b669f237
--- /dev/null
+++ b/lib/Expr/ArrayCache.cpp
@@ -0,0 +1,47 @@
+#include "klee/util/ArrayCache.h"
+
+namespace klee {
+
+ArrayCache::~ArrayCache() {
+ // Free Allocated Array objects
+ for (ArrayHashMap::iterator ai = cachedSymbolicArrays.begin(),
+ e = cachedSymbolicArrays.end();
+ ai != e; ++ai) {
+ delete *ai;
+ }
+ for (ArrayPtrVec::iterator ai = concreteArrays.begin(),
+ e = concreteArrays.end();
+ ai != e; ++ai) {
+ delete *ai;
+ }
+}
+
+const Array *
+ArrayCache::CreateArray(const std::string &_name, uint64_t _size,
+ const ref<ConstantExpr> *constantValuesBegin,
+ const ref<ConstantExpr> *constantValuesEnd,
+ Expr::Width _domain, Expr::Width _range) {
+
+ const Array *array = new Array(_name, _size, constantValuesBegin,
+ constantValuesEnd, _domain, _range);
+ if (array->isSymbolicArray()) {
+ std::pair<ArrayHashMap::const_iterator, bool> success =
+ cachedSymbolicArrays.insert(array);
+ if (success.second) {
+ // Cache miss
+ return array;
+ }
+ // Cache hit
+ delete array;
+ array = *(success.first);
+ assert(array->isSymbolicArray() &&
+ "Cached symbolic array is no longer symbolic");
+ return array;
+ } else {
+ // Treat every constant array as distinct so we never cache them
+ assert(array->isConstantArray());
+ concreteArrays.push_back(array); // For deletion later
+ return array;
+ }
+}
+}
diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp
index baa85663..2c64aff4 100644
--- a/lib/Expr/Expr.cpp
+++ b/lib/Expr/Expr.cpp
@@ -494,41 +494,6 @@ unsigned Array::computeHash() {
hashValue = res;
return hashValue;
}
-
-std::map<unsigned, std::vector<const Array *> *> Array::symbolicArraySingletonMap;
-
-const Array * Array::CreateArray(const std::string &_name, uint64_t _size,
- const ref<ConstantExpr> *constantValuesBegin,
- const ref<ConstantExpr> *constantValuesEnd,
- Expr::Width _domain,
- Expr::Width _range) {
-
- const Array * array = new Array(_name, _size, constantValuesBegin, constantValuesEnd, _domain,_range);
- if (array->constantValues.size() == 0) { // symbolic array
- unsigned hash = array->hash();
- std::vector<const Array *> * bucket = Array::symbolicArraySingletonMap[hash];
- if (bucket){
- for (std::vector<const Array*>::const_iterator it = bucket->begin();
- it != bucket->end(); it ++){
- const Array* prospect = *it;
- if (prospect->size == array->size && prospect->name == array->name){
- delete array;
- return prospect;
- }
- }
- bucket->push_back(array);
- return array;
- } else {
- bucket = new std::vector<const Array *>();
- bucket->push_back(array);
- Array::symbolicArraySingletonMap[hash] = bucket;
- return array;
- }
- } else { // concrete array
- return array;
- }
-}
-
/***/
ref<Expr> ReadExpr::create(const UpdateList &ul, ref<Expr> index) {
diff --git a/lib/Expr/Parser.cpp b/lib/Expr/Parser.cpp
index 23a292fa..854f6d52 100644
--- a/lib/Expr/Parser.cpp
+++ b/lib/Expr/Parser.cpp
@@ -16,6 +16,7 @@
#include "klee/ExprBuilder.h"
#include "klee/Solver.h"
#include "klee/util/ExprPPrinter.h"
+#include "klee/util/ArrayCache.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -109,6 +110,7 @@ namespace {
const std::string Filename;
const MemoryBuffer *TheMemoryBuffer;
ExprBuilder *Builder;
+ ArrayCache TheArrayCache;
Lexer TheLexer;
unsigned MaxErrors;
@@ -521,10 +523,10 @@ DeclResult ParserImpl::ParseArrayDecl() {
const Identifier *Label = GetOrCreateIdentifier(Name);
const Array *Root;
if (!Values.empty())
- Root = Array::CreateArray(Label->Name, Size.get(),
- &Values[0], &Values[0] + Values.size());
+ Root = TheArrayCache.CreateArray(Label->Name, Size.get(), &Values[0],
+ &Values[0] + Values.size());
else
- Root = Array::CreateArray(Label->Name, Size.get());
+ Root = TheArrayCache.CreateArray(Label->Name, Size.get());
ArrayDecl *AD = new ArrayDecl(Label, Size.get(),
DomainType.get(), RangeType.get(), Root);
@@ -1306,7 +1308,9 @@ VersionResult ParserImpl::ParseVersionSpecifier() {
VersionResult Res = ParseVersion();
// Define update list to avoid use-of-undef errors.
if (!Res.isValid()) {
- Res = VersionResult(true, UpdateList(Array::CreateArray("", 0), NULL));
+ // FIXME: I'm not sure if this is right. Do we need a unique array here?
+ Res =
+ VersionResult(true, UpdateList(TheArrayCache.CreateArray("", 0), NULL));
}
if (Label)