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
signature.asc
Description: Digital signature
_______________________________________________ pspp-dev mailing list [email protected] http://lists.gnu.org/mailman/listinfo/pspp-dev
