From b8e82670ce244434e7570fc4b0459628bd6beee1 Mon Sep 17 00:00:00 2001
From: Craig Tiller <ctiller@google.com>
Date: Sat, 10 Oct 2015 13:52:47 -0700
Subject: [PATCH] Fix race conditions

---
 src/core/transport/metadata.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 1b48b48e09..68f23177eb 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -160,12 +160,10 @@ static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
 #endif
-  if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
-    /* This ref is dropped if grpc_mdelem_unref reaches 1,
-       but allows us to safely unref without taking the mdctx lock
-       until such time */
-    gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
+  if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
     md->context->mdtab_free--;
+  } else {
+    GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
   }
 }
 
@@ -537,7 +535,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
      this function - meaning that no adjustment to mdtab_free is necessary,
      simplifying the logic here to be just an atomic increment */
   /* use C assert to have this removed in opt builds */
-  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+  assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
   gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
   return gmd;
 }
@@ -555,8 +553,10 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
   if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     grpc_mdctx *ctx = md->context;
     lock(ctx);
-    GPR_ASSERT(1 == gpr_atm_full_fetch_add(&md->refcnt, -1));
-    ctx->mdtab_free++;
+    if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
+      ctx->mdtab_free++;
+      gpr_atm_no_barrier_store(&md->refcnt, 0);
+    }
     unlock(ctx);
   }
 }
-- 
GitLab