Merge branch 'master' of https://github.com/grpc/grpc into memtracking
diff --git a/Makefile b/Makefile
index 690b92f..488d6f4 100644
--- a/Makefile
+++ b/Makefile
@@ -2702,6 +2702,7 @@
     test/core/end2end/fixtures/proxy.c \
     test/core/iomgr/endpoint_tests.c \
     test/core/util/grpc_profiler.c \
+    test/core/util/memory_counters.c \
     test/core/util/mock_endpoint.c \
     test/core/util/parse_hexstring.c \
     test/core/util/port_posix.c \
@@ -2750,6 +2751,7 @@
     test/core/end2end/fixtures/proxy.c \
     test/core/iomgr/endpoint_tests.c \
     test/core/util/grpc_profiler.c \
+    test/core/util/memory_counters.c \
     test/core/util/mock_endpoint.c \
     test/core/util/parse_hexstring.c \
     test/core/util/port_posix.c \
diff --git a/build.yaml b/build.yaml
index e274b03..a6feea5 100644
--- a/build.yaml
+++ b/build.yaml
@@ -567,6 +567,7 @@
   - test/core/end2end/fixtures/proxy.h
   - test/core/iomgr/endpoint_tests.h
   - test/core/util/grpc_profiler.h
+  - test/core/util/memory_counters.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
   - test/core/util/port.h
@@ -577,6 +578,7 @@
   - test/core/end2end/fixtures/proxy.c
   - test/core/iomgr/endpoint_tests.c
   - test/core/util/grpc_profiler.c
+  - test/core/util/memory_counters.c
   - test/core/util/mock_endpoint.c
   - test/core/util/parse_hexstring.c
   - test/core/util/port_posix.c
diff --git a/include/grpc/support/string_util.h b/include/grpc/support/string_util.h
index 0abdb4a..f981bc0 100644
--- a/include/grpc/support/string_util.h
+++ b/include/grpc/support/string_util.h
@@ -34,6 +34,8 @@
 #ifndef GRPC_SUPPORT_STRING_UTIL_H
 #define GRPC_SUPPORT_STRING_UTIL_H
 
+#include <grpc/support/port_platform.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 28d2d78..97c40e8 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -74,7 +74,8 @@
     return dst;
   }
   dst->num_args = src_num_args + num_to_add;
-  dst->args = gpr_malloc(sizeof(grpc_arg) * dst->num_args);
+  dst->args =
+      dst->num_args ? gpr_malloc(sizeof(grpc_arg) * dst->num_args) : NULL;
   for (i = 0; i < src_num_args; i++) {
     dst->args[i] = copy_arg(&src->args[i]);
   }
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index cfb5251..aaeb384 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -450,7 +450,7 @@
                            &sockname_len)) {
         port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
         if (port > 0) {
-          allocated_addr = malloc(addr_len);
+          allocated_addr = gpr_malloc(addr_len);
           memcpy(allocated_addr, addr, addr_len);
           grpc_sockaddr_set_port(allocated_addr, port);
           addr = allocated_addr;
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index 9f9d7dc..6940dec 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -467,7 +467,7 @@
                            (struct sockaddr *)&sockname_temp, &sockname_len)) {
         port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
         if (port > 0) {
-          allocated_addr = malloc(addr_len);
+          allocated_addr = gpr_malloc(addr_len);
           memcpy(allocated_addr, addr, addr_len);
           grpc_sockaddr_set_port(allocated_addr, port);
           addr = allocated_addr;
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index a0b9709..2413117 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -328,7 +328,7 @@
                            &sockname_len)) {
         port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
         if (port > 0) {
-          allocated_addr = malloc(addr_len);
+          allocated_addr = gpr_malloc(addr_len);
           memcpy(allocated_addr, addr, addr_len);
           grpc_sockaddr_set_port(allocated_addr, port);
           addr = allocated_addr;
diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c
index 93e0b99..50082cd 100644
--- a/src/core/lib/profiling/basic_timers.c
+++ b/src/core/lib/profiling/basic_timers.c
@@ -208,6 +208,7 @@
 }
 
 static void rotate_log() {
+  /* Using malloc here, as this code could end up being called by gpr_malloc */
   gpr_timer_log *new = malloc(sizeof(*new));
   gpr_once_init(&g_once_init, init_output);
   new->num_entries = 0;
diff --git a/src/core/lib/support/log_linux.c b/src/core/lib/support/log_linux.c
index 6d4b63b..ff3febb 100644
--- a/src/core/lib/support/log_linux.c
+++ b/src/core/lib/support/log_linux.c
@@ -68,6 +68,7 @@
   }
   va_end(args);
   gpr_log_message(file, line, severity, message);
+  /* message has been allocated by vasprintf above, and needs free */
   free(message);
 }
 
diff --git a/src/core/lib/support/thd_posix.c b/src/core/lib/support/thd_posix.c
index 89832e3..2fc23bf 100644
--- a/src/core/lib/support/thd_posix.c
+++ b/src/core/lib/support/thd_posix.c
@@ -81,6 +81,7 @@
   thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
   GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
   if (!thread_started) {
+    /* don't use gpr_free, as this was allocated using malloc (see above) */
     free(a);
   }
   *t = (gpr_thd_id)p;
diff --git a/src/core/lib/surface/byte_buffer.c b/src/core/lib/surface/byte_buffer.c
index fb39c45..a093a37 100644
--- a/src/core/lib/surface/byte_buffer.c
+++ b/src/core/lib/surface/byte_buffer.c
@@ -44,7 +44,7 @@
 grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
     gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) {
   size_t i;
-  grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
+  grpc_byte_buffer *bb = gpr_malloc(sizeof(grpc_byte_buffer));
   bb->type = GRPC_BB_RAW;
   bb->data.raw.compression = compression;
   gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
@@ -57,7 +57,7 @@
 
 grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
     grpc_byte_buffer_reader *reader) {
-  grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
+  grpc_byte_buffer *bb = gpr_malloc(sizeof(grpc_byte_buffer));
   gpr_slice slice;
   bb->type = GRPC_BB_RAW;
   bb->data.raw.compression = GRPC_COMPRESS_NONE;
@@ -85,7 +85,7 @@
       gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer);
       break;
   }
-  free(bb);
+  gpr_free(bb);
 }
 
 size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index ad8ee8c..e3b54ac 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -251,7 +251,9 @@
     count++;
   }
   cb->num_channels = count;
-  cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels);
+  cb->channels = cb->num_channels
+                     ? gpr_malloc(sizeof(*cb->channels) * cb->num_channels)
+                     : NULL;
   count = 0;
   for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
     cb->channels[count++] = c->channel;
diff --git a/src/core/lib/tsi/fake_transport_security.c b/src/core/lib/tsi/fake_transport_security.c
index 4b045b8..0e20d6f 100644
--- a/src/core/lib/tsi/fake_transport_security.c
+++ b/src/core/lib/tsi/fake_transport_security.c
@@ -36,6 +36,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/useful.h>
@@ -134,12 +135,12 @@
 static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) {
   if (frame->data == NULL) {
     frame->allocated_size = frame->size;
-    frame->data = malloc(frame->allocated_size);
+    frame->data = gpr_malloc(frame->allocated_size);
     if (frame->data == NULL) return 0;
   } else if (frame->size > frame->allocated_size) {
-    unsigned char *new_data = realloc(frame->data, frame->size);
+    unsigned char *new_data = gpr_realloc(frame->data, frame->size);
     if (new_data == NULL) {
-      free(frame->data);
+      gpr_free(frame->data);
       frame->data = NULL;
       return 0;
     }
@@ -160,7 +161,7 @@
   if (frame->needs_draining) return TSI_INTERNAL_ERROR;
   if (frame->data == NULL) {
     frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE;
-    frame->data = malloc(frame->allocated_size);
+    frame->data = gpr_malloc(frame->allocated_size);
     if (frame->data == NULL) return TSI_OUT_OF_RESOURCES;
   }
 
@@ -226,7 +227,7 @@
 }
 
 static void tsi_fake_frame_destruct(tsi_fake_frame *frame) {
-  if (frame->data != NULL) free(frame->data);
+  if (frame->data != NULL) gpr_free(frame->data);
 }
 
 /* --- tsi_frame_protector methods implementation. ---*/
@@ -366,7 +367,7 @@
   tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
   tsi_fake_frame_destruct(&impl->protect_frame);
   tsi_fake_frame_destruct(&impl->unprotect_frame);
-  free(self);
+  gpr_free(self);
 }
 
 static const tsi_frame_protector_vtable frame_protector_vtable = {
@@ -488,7 +489,7 @@
   tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
   tsi_fake_frame_destruct(&impl->incoming);
   tsi_fake_frame_destruct(&impl->outgoing);
-  free(self);
+  gpr_free(self);
 }
 
 static const tsi_handshaker_vtable handshaker_vtable = {
@@ -501,7 +502,8 @@
 };
 
 tsi_handshaker *tsi_create_fake_handshaker(int is_client) {
-  tsi_fake_handshaker *impl = calloc(1, sizeof(tsi_fake_handshaker));
+  tsi_fake_handshaker *impl = gpr_malloc(sizeof(*impl));
+  memset(impl, 0, sizeof(*impl));
   impl->base.vtable = &handshaker_vtable;
   impl->is_client = is_client;
   impl->result = TSI_HANDSHAKE_IN_PROGRESS;
@@ -517,8 +519,8 @@
 
 tsi_frame_protector *tsi_create_fake_protector(
     size_t *max_protected_frame_size) {
-  tsi_fake_frame_protector *impl = calloc(1, sizeof(tsi_fake_frame_protector));
-  if (impl == NULL) return NULL;
+  tsi_fake_frame_protector *impl = gpr_malloc(sizeof(*impl));
+  memset(impl, 0, sizeof(*impl));
   impl->max_frame_size = (max_protected_frame_size == NULL)
                              ? TSI_FAKE_DEFAULT_FRAME_SIZE
                              : *max_protected_frame_size;
diff --git a/src/core/lib/tsi/ssl_transport_security.c b/src/core/lib/tsi/ssl_transport_security.c
index d98b3e1..045901c 100644
--- a/src/core/lib/tsi/ssl_transport_security.c
+++ b/src/core/lib/tsi/ssl_transport_security.c
@@ -45,6 +45,7 @@
 #include <arpa/inet.h>
 #endif
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
@@ -148,8 +149,7 @@
   OpenSSL_add_all_algorithms();
   num_locks = CRYPTO_num_locks();
   GPR_ASSERT(num_locks > 0);
-  openssl_mutexes = malloc((size_t)num_locks * sizeof(gpr_mu));
-  GPR_ASSERT(openssl_mutexes != NULL);
+  openssl_mutexes = gpr_malloc((size_t)num_locks * sizeof(gpr_mu));
   for (i = 0; i < CRYPTO_num_locks(); i++) {
     gpr_mu_init(&openssl_mutexes[i]);
   }
@@ -701,7 +701,7 @@
     }
     *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1;
   }
-  *protocol_name_list = malloc(*protocol_name_list_length);
+  *protocol_name_list = gpr_malloc(*protocol_name_list_length);
   if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
   current = *protocol_name_list;
   for (i = 0; i < num_alpn_protocols; i++) {
@@ -852,9 +852,9 @@
 
 static void ssl_protector_destroy(tsi_frame_protector *self) {
   tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
-  if (impl->buffer != NULL) free(impl->buffer);
+  if (impl->buffer != NULL) gpr_free(impl->buffer);
   if (impl->ssl != NULL) SSL_free(impl->ssl);
-  free(self);
+  gpr_free(self);
 }
 
 static const tsi_frame_protector_vtable frame_protector_vtable = {
@@ -966,8 +966,9 @@
   if (alpn_selected != NULL) {
     size_t i;
     tsi_peer_property *new_properties =
-        calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1));
-    if (new_properties == NULL) return TSI_OUT_OF_RESOURCES;
+        gpr_malloc(sizeof(*new_properties) * (peer->property_count + 1));
+    memset(new_properties, 0,
+           sizeof(*new_properties) * (peer->property_count + 1));
     for (i = 0; i < peer->property_count; i++) {
       new_properties[i] = peer->properties[i];
     }
@@ -975,10 +976,10 @@
         TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected,
         alpn_selected_len, &new_properties[peer->property_count]);
     if (result != TSI_OK) {
-      free(new_properties);
+      gpr_free(new_properties);
       return result;
     }
-    if (peer->properties != NULL) free(peer->properties);
+    if (peer->properties != NULL) gpr_free(peer->properties);
     peer->property_count++;
     peer->properties = new_properties;
   }
@@ -991,11 +992,8 @@
   size_t actual_max_output_protected_frame_size =
       TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
   tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
-  tsi_ssl_frame_protector *protector_impl =
-      calloc(1, sizeof(tsi_ssl_frame_protector));
-  if (protector_impl == NULL) {
-    return TSI_OUT_OF_RESOURCES;
-  }
+  tsi_ssl_frame_protector *protector_impl = gpr_malloc(sizeof(*protector_impl));
+  memset(protector_impl, 0, sizeof(*protector_impl));
 
   if (max_output_protected_frame_size != NULL) {
     if (*max_output_protected_frame_size >
@@ -1011,11 +1009,11 @@
   }
   protector_impl->buffer_size =
       actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
-  protector_impl->buffer = malloc(protector_impl->buffer_size);
+  protector_impl->buffer = gpr_malloc(protector_impl->buffer_size);
   if (protector_impl->buffer == NULL) {
     gpr_log(GPR_ERROR,
             "Could not allocated buffer for tsi_ssl_frame_protector.");
-    free(protector_impl);
+    gpr_free(protector_impl);
     return TSI_INTERNAL_ERROR;
   }
 
@@ -1034,7 +1032,7 @@
 static void ssl_handshaker_destroy(tsi_handshaker *self) {
   tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
   SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
-  free(impl);
+  gpr_free(impl);
 }
 
 static const tsi_handshaker_vtable handshaker_vtable = {
@@ -1111,11 +1109,8 @@
     SSL_set_accept_state(ssl);
   }
 
-  impl = calloc(1, sizeof(tsi_ssl_handshaker));
-  if (impl == NULL) {
-    SSL_free(ssl);
-    return TSI_OUT_OF_RESOURCES;
-  }
+  impl = gpr_malloc(sizeof(*impl));
+  memset(impl, 0, sizeof(*impl));
   impl->ssl = ssl;
   impl->into_ssl = into_ssl;
   impl->from_ssl = from_ssl;
@@ -1167,8 +1162,8 @@
   tsi_ssl_client_handshaker_factory *impl =
       (tsi_ssl_client_handshaker_factory *)self;
   if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context);
-  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
-  free(impl);
+  if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list);
+  gpr_free(impl);
 }
 
 static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out,
@@ -1209,12 +1204,12 @@
       tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]);
     }
   }
-  if (impl->ssl_contexts != NULL) free(impl->ssl_contexts);
+  if (impl->ssl_contexts != NULL) gpr_free(impl->ssl_contexts);
   if (impl->ssl_context_x509_subject_names != NULL) {
-    free(impl->ssl_context_x509_subject_names);
+    gpr_free(impl->ssl_context_x509_subject_names);
   }
-  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list);
-  free(impl);
+  if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list);
+  gpr_free(impl);
 }
 
 static int does_entry_match_name(const char *entry, size_t entry_length,
@@ -1333,11 +1328,8 @@
     return TSI_INVALID_ARGUMENT;
   }
 
-  impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory));
-  if (impl == NULL) {
-    SSL_CTX_free(ssl_context);
-    return TSI_OUT_OF_RESOURCES;
-  }
+  impl = gpr_malloc(sizeof(*impl));
+  memset(impl, 0, sizeof(*impl));
   impl->ssl_context = ssl_context;
 
   do {
@@ -1411,14 +1403,17 @@
     return TSI_INVALID_ARGUMENT;
   }
 
-  impl = calloc(1, sizeof(tsi_ssl_server_handshaker_factory));
-  if (impl == NULL) return TSI_OUT_OF_RESOURCES;
+  impl = gpr_malloc(sizeof(*impl));
+  memset(impl, 0, sizeof(*impl));
   impl->base.create_handshaker =
       ssl_server_handshaker_factory_create_handshaker;
   impl->base.destroy = ssl_server_handshaker_factory_destroy;
-  impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX *));
+  impl->ssl_contexts = gpr_malloc(key_cert_pair_count * sizeof(SSL_CTX *));
+  memset(impl->ssl_contexts, 0, key_cert_pair_count * sizeof(SSL_CTX *));
   impl->ssl_context_x509_subject_names =
-      calloc(key_cert_pair_count, sizeof(tsi_peer));
+      gpr_malloc(key_cert_pair_count * sizeof(tsi_peer));
+  memset(impl->ssl_context_x509_subject_names, 0,
+         key_cert_pair_count * sizeof(tsi_peer));
   if (impl->ssl_contexts == NULL ||
       impl->ssl_context_x509_subject_names == NULL) {
     tsi_ssl_handshaker_factory_destroy(&impl->base);
diff --git a/src/core/lib/tsi/transport_security.c b/src/core/lib/tsi/transport_security.c
index 861fc79..830cf09 100644
--- a/src/core/lib/tsi/transport_security.c
+++ b/src/core/lib/tsi/transport_security.c
@@ -33,6 +33,9 @@
 
 #include "src/core/lib/tsi/transport_security.h"
 
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -40,19 +43,6 @@
 
 int tsi_tracing_enabled = 0;
 
-/* --- Utils. --- */
-
-char *tsi_strdup(const char *src) {
-  char *dst;
-  size_t len;
-  if (!src) return NULL;
-  len = strlen(src) + 1;
-  dst = malloc(len);
-  if (!dst) return NULL;
-  memcpy(dst, src, len);
-  return dst;
-}
-
 /* --- tsi_result common implementation. --- */
 
 const char *tsi_result_to_string(tsi_result result) {
@@ -214,15 +204,15 @@
   for (i = 0; i < child_count; i++) {
     tsi_peer_property_destruct(&children[i]);
   }
-  free(children);
+  gpr_free(children);
 }
 
 void tsi_peer_property_destruct(tsi_peer_property *property) {
   if (property->name != NULL) {
-    free(property->name);
+    gpr_free(property->name);
   }
   if (property->value.data != NULL) {
-    free(property->value.data);
+    gpr_free(property->value.data);
   }
   *property = tsi_init_peer_property(); /* Reset everything to 0. */
 }
@@ -239,16 +229,10 @@
 tsi_result tsi_construct_allocated_string_peer_property(
     const char *name, size_t value_length, tsi_peer_property *property) {
   *property = tsi_init_peer_property();
-  if (name != NULL) {
-    property->name = tsi_strdup(name);
-    if (property->name == NULL) return TSI_OUT_OF_RESOURCES;
-  }
+  if (name != NULL) property->name = gpr_strdup(name);
   if (value_length > 0) {
-    property->value.data = calloc(1, value_length);
-    if (property->value.data == NULL) {
-      tsi_peer_property_destruct(property);
-      return TSI_OUT_OF_RESOURCES;
-    }
+    property->value.data = gpr_malloc(value_length);
+    memset(property->value.data, 0, value_length);
     property->value.length = value_length;
   }
   return TSI_OK;
@@ -276,8 +260,8 @@
 tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) {
   memset(peer, 0, sizeof(tsi_peer));
   if (property_count > 0) {
-    peer->properties = calloc(property_count, sizeof(tsi_peer_property));
-    if (peer->properties == NULL) return TSI_OUT_OF_RESOURCES;
+    peer->properties = gpr_malloc(property_count * sizeof(tsi_peer_property));
+    memset(peer->properties, 0, property_count * sizeof(tsi_peer_property));
     peer->property_count = property_count;
   }
   return TSI_OK;
diff --git a/test/core/end2end/fuzzers/server_fuzzer.c b/test/core/end2end/fuzzers/server_fuzzer.c
index 393d330..4027371 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.c
+++ b/test/core/end2end/fuzzers/server_fuzzer.c
@@ -35,6 +35,7 @@
 
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/surface/server.h"
+#include "test/core/util/memory_counters.h"
 #include "test/core/util/mock_endpoint.h"
 
 static const bool squelch = true;
@@ -48,7 +49,9 @@
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   grpc_test_only_set_metadata_hash_seed(0);
+  struct grpc_memory_counters counters;
   if (squelch) gpr_set_log_function(dont_log);
+  grpc_memory_counters_init();
   grpc_init();
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
@@ -117,5 +120,8 @@
   grpc_server_destroy(server);
   grpc_completion_queue_destroy(cq);
   grpc_shutdown();
+  counters = grpc_memory_counters_snapshot();
+  grpc_memory_counters_destroy();
+  GPR_ASSERT(counters.total_size_relative == 0);
   return 0;
 }
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index 9b3b033..52082c3 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -89,7 +89,7 @@
 static gpr_slice *allocate_blocks(size_t num_bytes, size_t slice_size,
                                   size_t *num_blocks, uint8_t *current_data) {
   size_t nslices = num_bytes / slice_size + (num_bytes % slice_size ? 1 : 0);
-  gpr_slice *slices = malloc(sizeof(gpr_slice) * nslices);
+  gpr_slice *slices = gpr_malloc(sizeof(gpr_slice) * nslices);
   size_t num_bytes_left = num_bytes;
   size_t i;
   size_t j;
@@ -164,7 +164,7 @@
       gpr_slice_buffer_addn(&state->outgoing, slices, nslices);
       grpc_endpoint_write(exec_ctx, state->write_ep, &state->outgoing,
                           &state->done_write);
-      free(slices);
+      gpr_free(slices);
       return;
     }
   }
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index d51b6b7..7a98fa0 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -97,7 +97,7 @@
 static size_t fill_socket_partial(int fd, size_t bytes) {
   ssize_t write_bytes;
   size_t total_bytes = 0;
-  unsigned char *buf = malloc(bytes);
+  unsigned char *buf = gpr_malloc(bytes);
   unsigned i;
   for (i = 0; i < bytes; ++i) {
     buf[i] = (uint8_t)(i % 256);
@@ -292,7 +292,7 @@
 }
 
 void drain_socket_blocking(int fd, size_t num_bytes, size_t read_size) {
-  unsigned char *buf = malloc(read_size);
+  unsigned char *buf = gpr_malloc(read_size);
   ssize_t bytes_read;
   size_t bytes_left = num_bytes;
   int flags;
diff --git a/test/core/json/fuzzer.c b/test/core/json/fuzzer.c
index 044db97..e94b41c 100644
--- a/test/core/json/fuzzer.c
+++ b/test/core/json/fuzzer.c
@@ -38,42 +38,12 @@
 #include <grpc/support/log.h>
 
 #include "src/core/lib/json/json.h"
-
-static size_t g_total_size = 0;
-static gpr_allocation_functions g_old_allocs;
-
-void *guard_malloc(size_t size) {
-  size_t *ptr;
-  g_total_size += size;
-  ptr = g_old_allocs.malloc_fn(size + sizeof(size));
-  *ptr++ = size;
-  return ptr;
-}
-
-void *guard_realloc(void *vptr, size_t size) {
-  size_t *ptr = vptr;
-  --ptr;
-  g_total_size -= *ptr;
-  ptr = g_old_allocs.realloc_fn(ptr, size + sizeof(size));
-  g_total_size += size;
-  *ptr++ = size;
-  return ptr;
-}
-
-void guard_free(void *vptr) {
-  size_t *ptr = vptr;
-  --ptr;
-  g_total_size -= *ptr;
-  g_old_allocs.free_fn(ptr);
-}
-
-struct gpr_allocation_functions g_guard_allocs = {guard_malloc, guard_realloc,
-                                                  guard_free};
+#include "test/core/util/memory_counters.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   char *s;
-  g_old_allocs = gpr_get_allocation_functions();
-  gpr_set_allocation_functions(g_guard_allocs);
+  struct grpc_memory_counters counters;
+  grpc_memory_counters_init();
   s = gpr_malloc(size);
   memcpy(s, data, size);
   grpc_json *x;
@@ -81,7 +51,8 @@
     grpc_json_destroy(x);
   }
   gpr_free(s);
-  gpr_set_allocation_functions(g_old_allocs);
-  GPR_ASSERT(g_total_size == 0);
+  counters = grpc_memory_counters_snapshot();
+  grpc_memory_counters_destroy();
+  GPR_ASSERT(counters.total_size_relative == 0);
   return 0;
 }
diff --git a/test/core/network_benchmarks/low_level_ping_pong.c b/test/core/network_benchmarks/low_level_ping_pong.c
index ac5ee72..b3a38a5 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.c
+++ b/test/core/network_benchmarks/low_level_ping_pong.c
@@ -265,19 +265,19 @@
 #endif
 
 static void server_thread(thread_args *args) {
-  char *buf = malloc(args->msg_size);
+  char *buf = gpr_malloc(args->msg_size);
   if (args->setup(args) < 0) {
     gpr_log(GPR_ERROR, "Setup failed");
   }
   for (;;) {
     if (args->read_bytes(args, buf) < 0) {
       gpr_log(GPR_ERROR, "Server read failed");
-      free(buf);
+      gpr_free(buf);
       return;
     }
     if (args->write_bytes(args, buf) < 0) {
       gpr_log(GPR_ERROR, "Server write failed");
-      free(buf);
+      gpr_free(buf);
       return;
     }
   }
@@ -304,7 +304,8 @@
 }
 
 static void client_thread(thread_args *args) {
-  char *buf = calloc(args->msg_size, sizeof(char));
+  char *buf = gpr_malloc(args->msg_size * sizeof(char));
+  memset(buf, 0, args->msg_size * sizeof(char));
   gpr_histogram *histogram = gpr_histogram_create(0.01, 60e9);
   double start_time;
   double end_time;
@@ -333,7 +334,7 @@
   }
   print_histogram(histogram);
 error:
-  free(buf);
+  gpr_free(buf);
   gpr_histogram_destroy(histogram);
 }
 
@@ -596,8 +597,8 @@
     test_strategy *strategy = &test_strategies[i];
     size_t j;
     for (j = 0; j < GPR_ARRAY_SIZE(socket_types); ++j) {
-      thread_args *client_args = malloc(sizeof(thread_args));
-      thread_args *server_args = malloc(sizeof(thread_args));
+      thread_args *client_args = gpr_malloc(sizeof(thread_args));
+      thread_args *server_args = gpr_malloc(sizeof(thread_args));
       char *socket_type = socket_types[j];
 
       client_args->read_bytes = strategy->read_strategy;
@@ -620,8 +621,8 @@
 }
 
 int main(int argc, char **argv) {
-  thread_args *client_args = malloc(sizeof(thread_args));
-  thread_args *server_args = malloc(sizeof(thread_args));
+  thread_args *client_args = gpr_malloc(sizeof(thread_args));
+  thread_args *server_args = gpr_malloc(sizeof(thread_args));
   int msg_size = -1;
   char *read_strategy = NULL;
   char *socket_type = NULL;
diff --git a/test/core/support/alloc_test.c b/test/core/support/alloc_test.c
index a7df197..451c580 100644
--- a/test/core/support/alloc_test.c
+++ b/test/core/support/alloc_test.c
@@ -46,7 +46,7 @@
 static void test_custom_allocs() {
   const gpr_allocation_functions default_fns = gpr_get_allocation_functions();
   intptr_t addr_to_free = 0;
-  int *i;
+  char *i;
   gpr_allocation_functions fns = {fake_malloc, fake_realloc, fake_free};
 
   gpr_set_allocation_functions(fns);
@@ -58,7 +58,7 @@
 
   /* Restore and check we don't get funky values and that we don't leak */
   gpr_set_allocation_functions(default_fns);
-  GPR_ASSERT((void *)1 != (i = gpr_malloc(sizeof(*i))));
+  GPR_ASSERT((void *)sizeof(*i) != (i = gpr_malloc(sizeof(*i))));
   GPR_ASSERT((void *)2 != (i = gpr_realloc(i, 2)));
   gpr_free(i);
 }
diff --git a/test/core/util/memory_counters.c b/test/core/util/memory_counters.c
new file mode 100644
index 0000000..bebe94e
--- /dev/null
+++ b/test/core/util/memory_counters.c
@@ -0,0 +1,117 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/sync.h>
+
+#include "test/core/util/memory_counters.h"
+
+static gpr_mu g_memory_mutex;
+static struct grpc_memory_counters g_memory_counters;
+static gpr_allocation_functions g_old_allocs;
+
+static void *guard_malloc(size_t size);
+static void *guard_realloc(void *vptr, size_t size);
+static void guard_free(void *vptr);
+
+static void *guard_malloc(size_t size) {
+  size_t *ptr;
+  if (!size) return NULL;
+  gpr_mu_lock(&g_memory_mutex);
+  g_memory_counters.total_size_absolute += size;
+  g_memory_counters.total_size_relative += size;
+  g_memory_counters.total_allocs_absolute++;
+  g_memory_counters.total_allocs_relative++;
+  gpr_mu_unlock(&g_memory_mutex);
+  ptr = g_old_allocs.malloc_fn(size + sizeof(size));
+  *ptr++ = size;
+  return ptr;
+}
+
+static void *guard_realloc(void *vptr, size_t size) {
+  size_t *ptr = vptr;
+  if (vptr == NULL) {
+    return guard_malloc(size);
+  }
+  if (size == 0) {
+    guard_free(vptr);
+    return NULL;
+  }
+  --ptr;
+  gpr_mu_lock(&g_memory_mutex);
+  g_memory_counters.total_size_absolute += size;
+  g_memory_counters.total_size_relative -= *ptr;
+  g_memory_counters.total_size_relative += size;
+  g_memory_counters.total_allocs_absolute++;
+  gpr_mu_unlock(&g_memory_mutex);
+  ptr = g_old_allocs.realloc_fn(ptr, size + sizeof(size));
+  *ptr++ = size;
+  return ptr;
+}
+
+static void guard_free(void *vptr) {
+  size_t *ptr = vptr;
+  if (!vptr) return;
+  --ptr;
+  gpr_mu_lock(&g_memory_mutex);
+  g_memory_counters.total_size_relative -= *ptr;
+  g_memory_counters.total_allocs_relative--;
+  gpr_mu_unlock(&g_memory_mutex);
+  g_old_allocs.free_fn(ptr);
+}
+
+struct gpr_allocation_functions g_guard_allocs = {guard_malloc, guard_realloc,
+                                                  guard_free};
+
+void grpc_memory_counters_init() {
+  memset(&g_memory_counters, 0, sizeof(g_memory_counters));
+  gpr_mu_init(&g_memory_mutex);
+  g_old_allocs = gpr_get_allocation_functions();
+  gpr_set_allocation_functions(g_guard_allocs);
+}
+
+void grpc_memory_counters_destroy() {
+  gpr_set_allocation_functions(g_old_allocs);
+  gpr_mu_destroy(&g_memory_mutex);
+}
+
+struct grpc_memory_counters grpc_memory_counters_snapshot() {
+  struct grpc_memory_counters counters;
+  gpr_mu_lock(&g_memory_mutex);
+  counters = g_memory_counters;
+  gpr_mu_unlock(&g_memory_mutex);
+  return counters;
+}
diff --git a/test/core/util/memory_counters.h b/test/core/util/memory_counters.h
new file mode 100644
index 0000000..f332816
--- /dev/null
+++ b/test/core/util/memory_counters.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
+#define GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
+
+struct grpc_memory_counters {
+  size_t total_size_relative;
+  size_t total_size_absolute;
+  size_t total_allocs_relative;
+  size_t total_allocs_absolute;
+};
+
+void grpc_memory_counters_init();
+void grpc_memory_counters_destroy();
+struct grpc_memory_counters grpc_memory_counters_snapshot();
+
+#endif
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index ca409e3..0b68315 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -6226,6 +6226,7 @@
       "test/core/end2end/fixtures/proxy.h", 
       "test/core/iomgr/endpoint_tests.h", 
       "test/core/util/grpc_profiler.h", 
+      "test/core/util/memory_counters.h", 
       "test/core/util/mock_endpoint.h", 
       "test/core/util/parse_hexstring.h", 
       "test/core/util/port.h", 
@@ -6243,6 +6244,8 @@
       "test/core/iomgr/endpoint_tests.h", 
       "test/core/util/grpc_profiler.c", 
       "test/core/util/grpc_profiler.h", 
+      "test/core/util/memory_counters.c", 
+      "test/core/util/memory_counters.h", 
       "test/core/util/mock_endpoint.c", 
       "test/core/util/mock_endpoint.h", 
       "test/core/util/parse_hexstring.c", 
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index cb033a5..d1f67ee 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -153,6 +153,7 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\memory_counters.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\mock_endpoint.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\parse_hexstring.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
@@ -176,6 +177,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\memory_counters.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\mock_endpoint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\parse_hexstring.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 81b2a81..2fee6aa 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -25,6 +25,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\memory_counters.c">
+      <Filter>test\core\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\mock_endpoint.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
@@ -63,6 +66,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\memory_counters.h">
+      <Filter>test\core\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\util\mock_endpoint.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
index bb93b2c..3368253 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj
@@ -151,6 +151,7 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\fixtures\proxy.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\iomgr\endpoint_tests.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\memory_counters.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\mock_endpoint.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\parse_hexstring.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
@@ -166,6 +167,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\memory_counters.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\mock_endpoint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\parse_hexstring.c">
diff --git a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
index 4c4620a..5c2b961 100644
--- a/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util_unsecure/grpc_test_util_unsecure.vcxproj.filters
@@ -13,6 +13,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\grpc_profiler.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\util\memory_counters.c">
+      <Filter>test\core\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\mock_endpoint.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
@@ -45,6 +48,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\grpc_profiler.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\core\util\memory_counters.h">
+      <Filter>test\core\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\core\util\mock_endpoint.h">
       <Filter>test\core\util</Filter>
     </ClInclude>