about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--include/klee/util/Ref.h29
-rwxr-xr-xunittests/Makefile2
-rw-r--r--unittests/Ref/Makefile19
-rw-r--r--unittests/Ref/RefTest.cpp31
4 files changed, 65 insertions, 16 deletions
diff --git a/include/klee/util/Ref.h b/include/klee/util/Ref.h
index 1b823f56..d14de471 100644
--- a/include/klee/util/Ref.h
+++ b/include/klee/util/Ref.h
@@ -32,15 +32,15 @@ public:
   ~ref () { dec (); }
 
 private:
-  void inc() {
+  void inc() const {
     if (ptr)
       ++ptr->refCount;
   }
-  
-  void dec() {
+
+  void dec() const {
     if (ptr && --ptr->refCount == 0)
       delete ptr;
-  }  
+  }
 
 public:
   template<class U> friend class ref;
@@ -49,19 +49,18 @@ public:
   ref(T *p) : ptr(p) {
     inc();
   }
-  
+
   // normal copy constructor
   ref(const ref<T> &r) : ptr(r.ptr) {
     inc();
   }
-  
+
   // conversion constructor
   template<class U>
-  ref (const ref<U> &r) {
-    ptr = r.ptr;
+  ref (const ref<U> &r) : ptr(r.ptr) {
     inc();
   }
-  
+
   // pointer operations
   T *get () const {
     return ptr;
@@ -70,18 +69,18 @@ public:
   /* The copy assignment operator must also explicitly be defined,
    * despite a redundant template. */
   ref<T> &operator= (const ref<T> &r) {
+    r.inc();
     dec();
     ptr = r.ptr;
-    inc();
-    
+
     return *this;
   }
-  
+
   template<class U> ref<T> &operator= (const ref<U> &r) {
+    r.inc();
     dec();
     ptr = r.ptr;
-    inc();
-    
+
     return *this;
   }
 
@@ -130,7 +129,7 @@ struct simplify_type<const ::klee::ref<T> > {
   }
 };
 
-template<typename T> 
+template<typename T>
 struct simplify_type< ::klee::ref<T> >
   : public simplify_type<const ::klee::ref<T> > {};
 }
diff --git a/unittests/Makefile b/unittests/Makefile
index 545d7fa7..761987d6 100755
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -10,7 +10,7 @@ CPP.Flags += -I$(LLVM_SRC_ROOT)/utils/unittest/googletest/include/
 CPP.Flags += -Wno-variadic-macros
 
 # FIXME: Parallel dirs is broken?
-DIRS = Expr Solver
+DIRS = Expr Solver Ref
 
 include $(LEVEL)/Makefile.common
 
diff --git a/unittests/Ref/Makefile b/unittests/Ref/Makefile
new file mode 100644
index 00000000..3117a5fd
--- /dev/null
+++ b/unittests/Ref/Makefile
@@ -0,0 +1,19 @@
+##===- unittests/Expr/Makefile -----------------------------*- Makefile -*-===##
+
+LEVEL := ../..
+include $(LEVEL)/Makefile.config
+
+TESTNAME := RefTest
+STP_LIBS := stp_c_interface.a stp_AST.a stp_bitvec.a \
+            stp_constantbv.a stp_sat.a stp_simplifier.a
+USEDLIBS := kleaverExpr.a kleeBasic.a
+ifeq ($(ENABLE_EXT_STP),0)
+  USEDLIBS += $(STP_LIBS)
+endif
+LINK_COMPONENTS := support
+
+include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
+
+ifeq ($(ENABLE_EXT_STP),1)
+  LIBS += -lstp
+endif
diff --git a/unittests/Ref/RefTest.cpp b/unittests/Ref/RefTest.cpp
new file mode 100644
index 00000000..229fd9a8
--- /dev/null
+++ b/unittests/Ref/RefTest.cpp
@@ -0,0 +1,31 @@
+/* Regression test for a bug caused by assigning a ref to itself.
+   More details at http://keeda.stanford.edu/pipermail/klee-commits/2012-February/000904.html */
+
+#include "gtest/gtest.h"
+#include <iostream>
+#include "klee/util/Ref.h"
+using klee::ref;
+
+int finished = 0;
+
+struct Expr
+{
+  int refCount;
+  Expr() : refCount(0) { 
+    //std::cout << "Expr(" << this << ") created\n"; 
+  }
+  ~Expr() { 
+    //std::cout << "Expr(" << this << ") destroyed\n"; 
+    EXPECT_EQ(finished, 1);
+  }
+};
+
+TEST(RefTest, SelfAssign) 
+{
+  struct Expr *r_e = new Expr();
+  ref<Expr> r(r_e);
+  EXPECT_EQ(r_e->refCount, 1);
+  r = r;
+  EXPECT_EQ(r_e->refCount, 1);
+  finished = 1;
+}