Merge branch 'master' into cq_limited_pollers
diff --git a/BUILD b/BUILD
index a919a63..12c6f35 100644
--- a/BUILD
+++ b/BUILD
@@ -39,7 +39,7 @@
      "grpc_proto_plugin", "grpc_cc_libraries")
 
 # This should be updated along with build.yaml
-g_stands_for = "gentle"
+g_stands_for = "gregarious"
 
 core_version = "3.0.0-dev"
 
diff --git a/build.yaml b/build.yaml
index cd38b3c..95e9fc1 100644
--- a/build.yaml
+++ b/build.yaml
@@ -13,7 +13,7 @@
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
   core_version: 4.0.0-dev
-  g_stands_for: gentle
+  g_stands_for: gregarious
   version: 1.4.0-dev
 filegroups:
 - name: census
diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md
index d2fc7a5..2078bb3 100644
--- a/doc/g_stands_for.md
+++ b/doc/g_stands_for.md
@@ -8,3 +8,4 @@
 - 1.1 'g' stands for 'good'
 - 1.2 'g' stands for 'green'
 - 1.3 'g' stands for 'gentle'
+- 1.4 'g' stands for 'gregarious'
diff --git a/include/grpc++/impl/codegen/proto_utils.h b/include/grpc++/impl/codegen/proto_utils.h
index 6df9de4..8c0c32b 100644
--- a/include/grpc++/impl/codegen/proto_utils.h
+++ b/include/grpc++/impl/codegen/proto_utils.h
@@ -52,7 +52,7 @@
 
 class GrpcBufferWriterPeer;
 
-const int kGrpcBufferWriterMaxBufferLength = 8192;
+const int kGrpcBufferWriterMaxBufferLength = 1024 * 1024;
 
 class GrpcBufferWriter final
     : public ::grpc::protobuf::io::ZeroCopyOutputStream {
diff --git a/src/core/ext/filters/client_channel/subchannel.c b/src/core/ext/filters/client_channel/subchannel.c
index 967e571..b2de85c 100644
--- a/src/core/ext/filters/client_channel/subchannel.c
+++ b/src/core/ext/filters/client_channel/subchannel.c
@@ -615,7 +615,7 @@
   elem->filter->start_transport_op(exec_ctx, elem, op);
 }
 
-static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
+static bool publish_transport_locked(grpc_exec_ctx *exec_ctx,
                                      grpc_subchannel *c) {
   grpc_connected_subchannel *con;
   grpc_channel_stack *stk;
@@ -631,15 +631,16 @@
   if (!grpc_channel_init_create_stack(exec_ctx, builder,
                                       GRPC_CLIENT_SUBCHANNEL)) {
     grpc_channel_stack_builder_destroy(exec_ctx, builder);
-    abort(); /* TODO(ctiller): what to do here (previously we just crashed) */
+    return false;
   }
   grpc_error *error = grpc_channel_stack_builder_finish(
       exec_ctx, builder, 0, 1, connection_destroy, NULL, (void **)&con);
   if (error != GRPC_ERROR_NONE) {
+    grpc_transport_destroy(exec_ctx, c->connecting_result.transport);
     gpr_log(GPR_ERROR, "error initializing subchannel stack: %s",
             grpc_error_string(error));
     GRPC_ERROR_UNREF(error);
-    abort(); /* TODO(ctiller): what to do here? */
+    return false;
   }
   stk = CHANNEL_STACK_FROM_CONNECTION(con);
   memset(&c->connecting_result, 0, sizeof(c->connecting_result));
@@ -656,7 +657,7 @@
     grpc_channel_stack_destroy(exec_ctx, stk);
     gpr_free(con);
     GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
-    return;
+    return false;
   }
 
   /* publish */
@@ -678,6 +679,7 @@
   /* signal completion */
   grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
                               GRPC_ERROR_NONE, "connected");
+  return true;
 }
 
 static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
@@ -688,8 +690,9 @@
   GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
   gpr_mu_lock(&c->mu);
   c->connecting = false;
-  if (c->connecting_result.transport != NULL) {
-    publish_transport_locked(exec_ctx, c);
+  if (c->connecting_result.transport != NULL &&
+      publish_transport_locked(exec_ctx, c)) {
+    /* do nothing, transport was published */
   } else if (c->disconnected) {
     GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
   } else {
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 22caf24..d898526 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -128,7 +128,9 @@
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {
   channel_data *cd = (channel_data *)elem->channel_data;
-  grpc_transport_destroy(exec_ctx, cd->transport);
+  if (cd->transport) {
+    grpc_transport_destroy(exec_ctx, cd->transport);
+  }
 }
 
 static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index f526653..1f0daf7 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -343,8 +343,16 @@
                                      grpc_channel_element_args *args) {
   grpc_security_connector *sc =
       grpc_security_connector_find_in_args(args->channel_args);
+  if (sc == NULL) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Security connector missing from client auth filter args");
+  }
   grpc_auth_context *auth_context =
       grpc_find_auth_context_in_args(args->channel_args);
+  if (auth_context == NULL) {
+    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Auth context missing from client auth filter args");
+  }
 
   /* grab pointers to our data from the channel element */
   channel_data *chand = elem->channel_data;
@@ -353,8 +361,6 @@
      handle the case that there's no 'next' filter to call on the up or down
      path */
   GPR_ASSERT(!args->is_last);
-  GPR_ASSERT(sc != NULL);
-  GPR_ASSERT(auth_context != NULL);
 
   /* initialize members */
   chand->security_connector =
diff --git a/src/core/lib/support/avl.c b/src/core/lib/support/avl.c
index acf8fd5..ffa10c1 100644
--- a/src/core/lib/support/avl.c
+++ b/src/core/lib/support/avl.c
@@ -205,8 +205,8 @@
   }
 }
 
-static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node,
-                         void *key, void *value) {
+static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node,
+                             void *key, void *value) {
   long cmp;
   if (node == NULL) {
     return new_node(key, value, NULL, NULL);
@@ -217,17 +217,17 @@
   } else if (cmp > 0) {
     return rebalance(
         vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
-        add(vtable, node->left, key, value), ref_node(node->right));
+        add_key(vtable, node->left, key, value), ref_node(node->right));
   } else {
     return rebalance(vtable, vtable->copy_key(node->key),
                      vtable->copy_value(node->value), ref_node(node->left),
-                     add(vtable, node->right, key, value));
+                     add_key(vtable, node->right, key, value));
   }
 }
 
 gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) {
   gpr_avl_node *old_root = avl.root;
-  avl.root = add(avl.vtable, avl.root, key, value);
+  avl.root = add_key(avl.vtable, avl.root, key, value);
   assert_invariants(avl.root);
   unref_node(avl.vtable, old_root);
   return avl;
@@ -247,8 +247,8 @@
   return node;
 }
 
-static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node,
-                            void *key) {
+static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable,
+                                gpr_avl_node *node, void *key) {
   long cmp;
   if (node == NULL) {
     return NULL;
@@ -263,27 +263,27 @@
       gpr_avl_node *h = in_order_head(node->right);
       return rebalance(vtable, vtable->copy_key(h->key),
                        vtable->copy_value(h->value), ref_node(node->left),
-                       remove(vtable, node->right, h->key));
+                       remove_key(vtable, node->right, h->key));
     } else {
       gpr_avl_node *h = in_order_tail(node->left);
       return rebalance(
           vtable, vtable->copy_key(h->key), vtable->copy_value(h->value),
-          remove(vtable, node->left, h->key), ref_node(node->right));
+          remove_key(vtable, node->left, h->key), ref_node(node->right));
     }
   } else if (cmp > 0) {
-    return rebalance(vtable, vtable->copy_key(node->key),
-                     vtable->copy_value(node->value),
-                     remove(vtable, node->left, key), ref_node(node->right));
+    return rebalance(
+        vtable, vtable->copy_key(node->key), vtable->copy_value(node->value),
+        remove_key(vtable, node->left, key), ref_node(node->right));
   } else {
     return rebalance(vtable, vtable->copy_key(node->key),
                      vtable->copy_value(node->value), ref_node(node->left),
-                     remove(vtable, node->right, key));
+                     remove_key(vtable, node->right, key));
   }
 }
 
 gpr_avl gpr_avl_remove(gpr_avl avl, void *key) {
   gpr_avl_node *old_root = avl.root;
-  avl.root = remove(avl.vtable, avl.root, key);
+  avl.root = remove_key(avl.vtable, avl.root, key);
   assert_invariants(avl.root);
   unref_node(avl.vtable, old_root);
   return avl;
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 3793845..cddc595 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -38,4 +38,4 @@
 
 const char *grpc_version_string(void) { return "4.0.0-dev"; }
 
-const char *grpc_g_stands_for(void) { return "gentle"; }
+const char *grpc_g_stands_for(void) { return "gregarious"; }
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index 3fc3185..28a2714 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -6,7 +6,7 @@
 Installation
 ------------
 
-gRPC Python is available for Linux, Mac OS X, and Windows running Python 2.7.
+gRPC Python is available for Linux, macOS, and Windows.
 
 From PyPI
 ~~~~~~~~~
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-5175380371570688 b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-5175380371570688
new file mode 100644
index 0000000..9c7aebc
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-5175380371570688
Binary files differ
diff --git a/test/core/end2end/tests/resource_quota_server.c b/test/core/end2end/tests/resource_quota_server.c
index 2453ca1..6418f5d 100644
--- a/test/core/end2end/tests/resource_quota_server.c
+++ b/test/core/end2end/tests/resource_quota_server.c
@@ -169,6 +169,7 @@
   int cancelled_calls_on_client = 0;
   int cancelled_calls_on_server = 0;
   int deadline_exceeded = 0;
+  int unavailable = 0;
 
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
@@ -260,6 +261,9 @@
         case GRPC_STATUS_DEADLINE_EXCEEDED:
           deadline_exceeded++;
           break;
+        case GRPC_STATUS_UNAVAILABLE:
+          unavailable++;
+          break;
         case GRPC_STATUS_OK:
           break;
         default:
@@ -358,9 +362,9 @@
 
   gpr_log(GPR_INFO,
           "Done. %d total calls: %d cancelled at server, %d cancelled at "
-          "client, %d timed out.",
+          "client, %d timed out, %d unavailable.",
           NUM_CALLS, cancelled_calls_on_server, cancelled_calls_on_client,
-          deadline_exceeded);
+          deadline_exceeded, unavailable);
 
   grpc_byte_buffer_destroy(request_payload);
   grpc_slice_unref(request_payload_slice);
diff --git a/tools/profiling/microbenchmarks/bm_diff.py b/tools/profiling/microbenchmarks/bm_diff.py
index 3c15478..b2d6f46 100755
--- a/tools/profiling/microbenchmarks/bm_diff.py
+++ b/tools/profiling/microbenchmarks/bm_diff.py
@@ -248,8 +248,8 @@
     text = 'Performance differences noted:\n' + tabulate.tabulate(rows, headers=headers, floatfmt='+.2f')
   else:
     text = 'No significant performance differences'
-  comment_on_pr.comment_on_pr('```\n%s\n```' % text)
   print text
+  comment_on_pr.comment_on_pr('```\n%s\n```' % text)
 
 
 eintr_be_gone(finalize)
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 0581278..2928b87 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -85304,6 +85304,29 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/clusterfuzz-testcase-minimized-5175380371570688"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/crash-0597bbdd657fa4ed14443994c9147a1a7bbc205f"
     ], 
     "ci_platforms": [