summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-06-20 14:27:59 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-08-31 19:06:56 +0200
commit5f1011ac0ad676d1e7eaba14d1384180e98fb93e (patch)
tree4c4b37623d138c593d4d9220e4444d39fde2abd9 /include
parent334801c52c9844c06eacbe2e3af65852f7412e3c (diff)
include: detect use-after-free errors using the reference counts
* include/refcount.h (refcount_init): There must be at least one reference at initialization time. (refcounts_init): Likewise. (refcount_unsafe_ref): New function retaining the previous functionality of refcount_ref. It is occasionally useful to raise the reference count again after it dropped to zero. (refcounts_unsafe_ref): Likewise. (refcounts_unsafe_weak_ref): Likewise. (refcount_ref): Detect use-after-free errors. (refcounts_ref): Likewise. (refcounts_ref_weak): Likewise. * libtrivfs/protid-clean.c (trivfs_clean_protid): Use refcount_unsafe_ref.
Diffstat (limited to 'include')
-rw-r--r--include/refcount.h73
1 files changed, 65 insertions, 8 deletions
diff --git a/include/refcount.h b/include/refcount.h
index 785b052a..ebde42da 100644
--- a/include/refcount.h
+++ b/include/refcount.h
@@ -31,18 +31,23 @@
/* An opaque type. You must not access these values directly. */
typedef unsigned int refcount_t;
-/* Initialize REF with REFERENCES. */
+/* Initialize REF with REFERENCES. REFERENCES must not be zero. */
static inline void
refcount_init (refcount_t *ref, unsigned int references)
{
+ assert (references > 0 || !"references must not be zero!");
*ref = references;
}
/* Increment REF. Return the result of the operation. This function
uses atomic operations. It is not required to serialize calls to
- this function. */
+ this function.
+
+ This is the unsafe version of refcount_ref. refcount_ref also
+ checks for use-after-free errors. When in doubt, use that one
+ instead. */
static inline unsigned int
-refcount_ref (refcount_t *ref)
+refcount_unsafe_ref (refcount_t *ref)
{
unsigned int r;
r = __atomic_add_fetch (ref, 1, __ATOMIC_RELAXED);
@@ -50,6 +55,18 @@ refcount_ref (refcount_t *ref)
return r;
}
+/* Increment REF. Return the result of the operation. This function
+ uses atomic operations. It is not required to serialize calls to
+ this function. */
+static inline unsigned int
+refcount_ref (refcount_t *ref)
+{
+ unsigned int r;
+ r = refcount_unsafe_ref (ref);
+ assert (r != 1 || !"refcount detected use-after-free!");
+ return r;
+}
+
/* Decrement REF. Return the result of the operation. This function
uses atomic operations. It is not required to serialize calls to
this function. */
@@ -101,19 +118,25 @@ union _references {
uint64_t value;
};
-/* Initialize REF with HARD and WEAK references. */
+/* Initialize REF with HARD and WEAK references. HARD and WEAK must
+ not both be zero. */
static inline void
refcounts_init (refcounts_t *ref, uint32_t hard, uint32_t weak)
{
+ assert ((hard != 0 || weak != 0) || !"references must not both be zero!");
ref->references = (struct references) { .hard = hard, .weak = weak };
}
/* Increment the hard reference count of REF. If RESULT is not NULL,
the result of the operation is written there. This function uses
atomic operations. It is not required to serialize calls to this
- function. */
+ function.
+
+ This is the unsafe version of refcounts_ref. refcounts_ref also
+ checks for use-after-free errors. When in doubt, use that one
+ instead. */
static inline void
-refcounts_ref (refcounts_t *ref, struct references *result)
+refcounts_unsafe_ref (refcounts_t *ref, struct references *result)
{
const union _references op = { .references = { .hard = 1 } };
union _references r;
@@ -123,6 +146,21 @@ refcounts_ref (refcounts_t *ref, struct references *result)
*result = r.references;
}
+/* Increment the hard reference count of REF. If RESULT is not NULL,
+ the result of the operation is written there. This function uses
+ atomic operations. It is not required to serialize calls to this
+ function. */
+static inline void
+refcounts_ref (refcounts_t *ref, struct references *result)
+{
+ struct references r;
+ refcounts_unsafe_ref (ref, &r);
+ assert (! (r.hard == 1 && r.weak == 0)
+ || !"refcount detected use-after-free!");
+ if (result)
+ *result = r;
+}
+
/* Decrement the hard reference count of REF. If RESULT is not NULL,
the result of the operation is written there. This function uses
atomic operations. It is not required to serialize calls to this
@@ -200,9 +238,13 @@ refcounts_demote (refcounts_t *ref, struct references *result)
/* Increment the weak reference count of REF. If RESULT is not NULL,
the result of the operation is written there. This function uses
atomic operations. It is not required to serialize calls to this
- function. */
+ function.
+
+ This is the unsafe version of refcounts_ref_weak.
+ refcounts_ref_weak also checks for use-after-free errors. When in
+ doubt, use that one instead. */
static inline void
-refcounts_ref_weak (refcounts_t *ref, struct references *result)
+refcounts_unsafe_ref_weak (refcounts_t *ref, struct references *result)
{
const union _references op = { .references = { .weak = 1 } };
union _references r;
@@ -212,6 +254,21 @@ refcounts_ref_weak (refcounts_t *ref, struct references *result)
*result = r.references;
}
+/* Increment the weak reference count of REF. If RESULT is not NULL,
+ the result of the operation is written there. This function uses
+ atomic operations. It is not required to serialize calls to this
+ function. */
+static inline void
+refcounts_ref_weak (refcounts_t *ref, struct references *result)
+{
+ struct references r;
+ refcounts_unsafe_ref_weak (ref, &r);
+ assert (! (r.hard == 0 && r.weak == 1)
+ || !"refcount detected use-after-free!");
+ if (result)
+ *result = r;
+}
+
/* Decrement the weak reference count of REF. If RESULT is not NULL,
the result of the operation is written there. This function uses
atomic operations. It is not required to serialize calls to this