Bladeren bron

[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 jaren geleden
bovenliggende
commit
6e41f2cf18
2 gewijzigde bestanden met toevoegingen van 52 en 12 verwijderingen
  1. 17
    9
      src/core/refcnt.c
  2. 35
    3
      src/include/ipxe/refcnt.h

+ 17
- 9
src/core/refcnt.c Bestand weergeven

@@ -31,18 +31,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
31 31
  * Increment reference count
32 32
  *
33 33
  * @v refcnt		Reference counter, or NULL
34
- * @ret refcnt		Reference counter
35 34
  *
36 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 39
 	if ( refcnt ) {
41
-		refcnt->refcnt++;
40
+		refcnt->count++;
42 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,18 +53,28 @@ struct refcnt * ref_get ( struct refcnt *refcnt ) {
55 53
  *
56 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 58
 	if ( ! refcnt )
61 59
 		return;
62 60
 
63
-	refcnt->refcnt--;
61
+	refcnt->count--;
64 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 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 78
 	if ( refcnt->free ) {
71 79
 		DBGC ( refcnt, "REFCNT %p being freed via method %p\n",
72 80
 		       refcnt, refcnt->free );

+ 35
- 3
src/include/ipxe/refcnt.h Bestand weergeven

@@ -9,6 +9,9 @@
9 9
 
10 10
 FILE_LICENCE ( GPL2_OR_LATER );
11 11
 
12
+#include <stddef.h>
13
+#include <assert.h>
14
+
12 15
 /**
13 16
  * A reference counter
14 17
  *
@@ -26,7 +29,7 @@ struct refcnt {
26 29
 	 * When this count is decremented below zero, the free()
27 30
 	 * method will be called.
28 31
 	 */
29
-	int refcnt;
32
+	int count;
30 33
 	/** Free containing object
31 34
 	 *
32 35
 	 * This method is called when the reference count is
@@ -75,8 +78,37 @@ ref_init ( struct refcnt *refcnt,
75 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 112
 extern void ref_no_free ( struct refcnt *refcnt );
81 113
 
82 114
 #endif /* _IPXE_REFCNT_H */

Laden…
Annuleren
Opslaan