+// TODO: move to os_refcnt once the ABI issue is resolved
+
+#define KAUTH_CRED_REF_MAX 0x0ffffffful
+
+__attribute__((noinline, cold, noreturn))
+static void
+kauth_cred_panic_resurrection(kauth_cred_t cred)
+{
+ panic("kauth_cred_unref: cred %p resurrected", cred);
+ __builtin_unreachable();
+}
+
+__attribute__((noinline, cold, noreturn))
+static void
+kauth_cred_panic_over_released(kauth_cred_t cred)
+{
+ panic("kauth_cred_unref: cred %p over-released", cred);
+ __builtin_unreachable();
+}
+
+__attribute__((noinline, cold, noreturn))
+static void
+kauth_cred_panic_over_retain(kauth_cred_t cred)
+{
+ panic("kauth_cred_ref: cred %p over-retained", cred);
+ __builtin_unreachable();
+}
+
+/*
+ * kauth_cred_tryref
+ *
+ * Description: Tries to take a reference, used from kauth_cred_find_and_ref
+ * to debounce the race with kauth_cred_unref.
+ *
+ * Parameters: cred The credential to reference
+ *
+ * Returns: (bool) Whether the reference was taken
+ */
+static inline bool
+kauth_cred_tryref(kauth_cred_t cred)
+{
+ u_long old_ref, new_ref;
+ os_atomic_rmw_loop(&cred->cr_ref, old_ref, new_ref, relaxed, {
+ if (old_ref == 0) {
+ os_atomic_rmw_loop_give_up(return false);
+ }
+ new_ref = old_ref + 1;
+ });
+ if (__improbable(old_ref >= KAUTH_CRED_REF_MAX)) {
+ kauth_cred_panic_over_retain(cred);
+ }
+
+#if 0 // use this to watch a specific credential
+ if (is_target_cred( *credp ) != 0) {
+ get_backtrace();
+ }
+#endif
+
+ return true;
+}
+