Browse Source

[refcnt] Check reference validity on each use of ref_get() and ref_put()

Check that the reference count is valid (i.e. non-negative) on each
call to ref_get() and ref_put(), using an assert() at the point of
use.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
6e41f2cf18
2 changed files with 52 additions and 12 deletions
  1. 17
    9
      src/core/refcnt.c
  2. 35
    3
      src/include/ipxe/refcnt.h

+ 17
- 9
src/core/refcnt.c View File

31
  * Increment reference count
31
  * Increment reference count
32
  *
32
  *
33
  * @v refcnt		Reference counter, or NULL
33
  * @v refcnt		Reference counter, or NULL
34
- * @ret refcnt		Reference counter
35
  *
34
  *
36
  * If @c refcnt is NULL, no action is taken.
35
  * If @c refcnt is NULL, no action is taken.
37
  */
36
  */
38
-struct refcnt * ref_get ( struct refcnt *refcnt ) {
37
+void ref_increment ( struct refcnt *refcnt ) {
39
 
38
 
40
 	if ( refcnt ) {
39
 	if ( refcnt ) {
41
-		refcnt->refcnt++;
40
+		refcnt->count++;
42
 		DBGC2 ( refcnt, "REFCNT %p incremented to %d\n",
41
 		DBGC2 ( refcnt, "REFCNT %p incremented to %d\n",
43
-			refcnt, refcnt->refcnt );
42
+			refcnt, refcnt->count );
44
 	}
43
 	}
45
-	return refcnt;
46
 }
44
 }
47
 
45
 
48
 /**
46
 /**
55
  *
53
  *
56
  * If @c refcnt is NULL, no action is taken.
54
  * If @c refcnt is NULL, no action is taken.
57
  */
55
  */
58
-void ref_put ( struct refcnt *refcnt ) {
56
+void ref_decrement ( struct refcnt *refcnt ) {
59
 
57
 
60
 	if ( ! refcnt )
58
 	if ( ! refcnt )
61
 		return;
59
 		return;
62
 
60
 
63
-	refcnt->refcnt--;
61
+	refcnt->count--;
64
 	DBGC2 ( refcnt, "REFCNT %p decremented to %d\n",
62
 	DBGC2 ( refcnt, "REFCNT %p decremented to %d\n",
65
-		refcnt, refcnt->refcnt );
63
+		refcnt, refcnt->count );
66
 
64
 
67
-	if ( refcnt->refcnt >= 0 )
65
+	if ( refcnt->count >= 0 )
68
 		return;
66
 		return;
69
 
67
 
68
+	if ( refcnt->count < -1 ) {
69
+		DBGC ( refcnt, "REFCNT %p decremented too far (%d)!\n",
70
+		       refcnt, refcnt->count );
71
+		/* Avoid multiple calls to free(), which typically
72
+		 * result in memory corruption that is very hard to
73
+		 * track down.
74
+		 */
75
+		return;
76
+	}
77
+
70
 	if ( refcnt->free ) {
78
 	if ( refcnt->free ) {
71
 		DBGC ( refcnt, "REFCNT %p being freed via method %p\n",
79
 		DBGC ( refcnt, "REFCNT %p being freed via method %p\n",
72
 		       refcnt, refcnt->free );
80
 		       refcnt, refcnt->free );

+ 35
- 3
src/include/ipxe/refcnt.h View File

9
 
9
 
10
 FILE_LICENCE ( GPL2_OR_LATER );
10
 FILE_LICENCE ( GPL2_OR_LATER );
11
 
11
 
12
+#include <stddef.h>
13
+#include <assert.h>
14
+
12
 /**
15
 /**
13
  * A reference counter
16
  * A reference counter
14
  *
17
  *
26
 	 * When this count is decremented below zero, the free()
29
 	 * When this count is decremented below zero, the free()
27
 	 * method will be called.
30
 	 * method will be called.
28
 	 */
31
 	 */
29
-	int refcnt;
32
+	int count;
30
 	/** Free containing object
33
 	/** Free containing object
31
 	 *
34
 	 *
32
 	 * This method is called when the reference count is
35
 	 * This method is called when the reference count is
75
 		.free = free_fn,					\
78
 		.free = free_fn,					\
76
 	}
79
 	}
77
 
80
 
78
-extern struct refcnt * ref_get ( struct refcnt *refcnt );
79
-extern void ref_put ( struct refcnt *refcnt );
81
+extern void ref_increment ( struct refcnt *refcnt );
82
+extern void ref_decrement ( struct refcnt *refcnt );
83
+
84
+/**
85
+ * Get additional reference to object
86
+ *
87
+ * @v refcnt		Reference counter, or NULL
88
+ * @ret refcnt		Reference counter
89
+ *
90
+ * If @c refcnt is NULL, no action is taken.
91
+ */
92
+#define ref_get( refcnt ) ( {						\
93
+	if ( refcnt )							\
94
+		assert ( (refcnt)->count >= 0 );			\
95
+	ref_increment ( refcnt );					\
96
+	(refcnt); } )
97
+
98
+/**
99
+ * Drop reference to object
100
+ *
101
+ * @v refcnt		Reference counter, or NULL
102
+ * @ret refcnt		Reference counter
103
+ *
104
+ * If @c refcnt is NULL, no action is taken.
105
+ */
106
+#define ref_put( refcnt ) do {						\
107
+	if ( refcnt )							\
108
+		assert ( (refcnt)->count >= 0 );			\
109
+	ref_decrement ( refcnt );					\
110
+	} while ( 0 )
111
+
80
 extern void ref_no_free ( struct refcnt *refcnt );
112
 extern void ref_no_free ( struct refcnt *refcnt );
81
 
113
 
82
 #endif /* _IPXE_REFCNT_H */
114
 #endif /* _IPXE_REFCNT_H */

Loading…
Cancel
Save