It's almost impossible to track down memory leaks when ref counted
objects are involved.  I'm proposing this patch to case.[ch] which
allows a preprocessor option to be set redefining case_ref and case_unref 
to unconditionally copy and destroy cases respectively.  

It would be easier to use if we could put the switch entirely inside case.c,
since almost everything depends upon case.h -- but we could only do that
if we sacrificed the benefits of the inline functions.


J'

-- 
PGP Public key ID: 1024D/2DE827B3 
fingerprint = 8797 A26D 0854 2EAB 0285  A290 8A67 719C 2DE8 27B3
See http://pgp.mit.edu or any PGP keyserver for public key.


diff --git a/src/data/case.c b/src/data/case.c
index dc40292..36aa539 100644
--- a/src/data/case.c
+++ b/src/data/case.c
@@ -65,7 +65,9 @@ case_try_create (const struct caseproto *proto)
       if (caseproto_try_init_values (proto, c->values))
         {
           c->proto = caseproto_ref (proto);
+#if ! DEBUG_CASEREFS
           c->ref_cnt = 1;
+#endif
           return c;
         }
       free (c);
@@ -148,7 +150,9 @@ case_unshare_and_resize (struct ccase *c, const struct caseproto *proto)
       size_t old_n_values = caseproto_get_n_widths (c->proto);
       size_t new_n_values = caseproto_get_n_widths (proto);
       case_copy (new, 0, c, 0, MIN (old_n_values, new_n_values));
+#if ! DEBUG_CASEREFS
       c->ref_cnt--;
+#endif
       return new;
     }
 }
@@ -420,7 +424,9 @@ case_unshare__ (struct ccase *old)
 {
   struct ccase *new = case_create (old->proto);
   case_copy (new, 0, old, 0, caseproto_get_n_widths (new->proto));
+#if ! DEBUG_CASEREFS
   --old->ref_cnt;
+#endif
   return new;
 }
 
diff --git a/src/data/case.h b/src/data/case.h
index d00c2ad..c6f68ae 100644
--- a/src/data/case.h
+++ b/src/data/case.h
@@ -24,6 +24,9 @@
 #include <libpspp/compiler.h>
 #include <data/caseproto.h>
 
+/* Set to non-zero to use deep copying instead of reference counting */
+#define DEBUG_CASEREFS 1
+
 struct variable;
 
 /* A count of cases or the index of a case within a collection of
@@ -52,7 +55,9 @@ typedef long int casenumber;
 struct ccase
   {
     struct caseproto *proto;    /* Case prototype. */
+#if DEGBUG_CASEREFS
     size_t ref_cnt;             /* Reference count. */
+#endif
     union value values[1];      /* Values. */
   };
 
@@ -61,7 +66,7 @@ struct ccase *case_try_create (const struct caseproto *) MALLOC_LIKE;
 struct ccase *case_clone (const struct ccase *) MALLOC_LIKE;
 
 static inline struct ccase *case_unshare (struct ccase *) WARN_UNUSED_RESULT;
-static inline struct ccase *case_ref (const struct ccase *);
+static inline struct ccase *case_ref (const struct ccase *) WARN_UNUSED_RESULT;
 static inline void case_unref (struct ccase *);
 static inline bool case_is_shared (const struct ccase *);
 
@@ -135,9 +140,13 @@ case_unshare (struct ccase *c)
 static inline struct ccase *
 case_ref (const struct ccase *c_)
 {
+#if DEBUG_CASEREFS
+  return case_unshare__ (CONST_CAST (struct ccase *,c_));
+#else
   struct ccase *c = CONST_CAST (struct ccase *, c_);
   c->ref_cnt++;
   return c;
+#endif
 }
 
 /* Decrements case C's reference count.  Frees C if its
@@ -147,18 +156,29 @@ case_ref (const struct ccase *c_)
 static inline void
 case_unref (struct ccase *c)
 {
-  if (c != NULL && !--c->ref_cnt)
-    case_unref__ (c);
+  if (c != NULL)
+#if ! DEBUG_CASEREFS
+    if (!--c->ref_cnt)
+#endif
+      case_unref__ (c);
 }
 
 /* Returns true if case C is shared.  A case that is shared
    cannot be modified directly.  Instead, an unshared copy must
    first be made with case_unshare(). */
+#if DEBUG_CASEREFS
+static inline bool
+case_is_shared (const struct ccase *c UNUSED)
+{
+  return false;
+}
+#else
 static inline bool
 case_is_shared (const struct ccase *c)
 {
   return c->ref_cnt > 1;
 }
+#endif
 
 /* Returns the number of union values in C. */
 static inline size_t

Attachment: signature.asc
Description: Digital signature

_______________________________________________
pspp-dev mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/pspp-dev

Reply via email to