Merge pull request #14017 from ZhouyihaiDing/php_channl_memory_leak

php: fix memory leak during creating channel
diff --git a/BUILD b/BUILD
index 804c6ce..ddcb0cd 100644
--- a/BUILD
+++ b/BUILD
@@ -39,6 +39,16 @@
 )
 
 config_setting(
+    name = "grpc_allow_exceptions",
+    values = {"define": "GRPC_ALLOW_EXCEPTIONS=1"},
+)
+
+config_setting(
+    name = "grpc_disallow_exceptions",
+    values = {"define": "GRPC_ALLOW_EXCEPTIONS=0"},
+)
+
+config_setting(
     name = "remote_execution",
     values = {"define": "GRPC_PORT_ISOLATED_RUNTIME=1"},
 )
@@ -544,24 +554,24 @@
 
 grpc_cc_library(
     name = "debug_location",
-    public_hdrs = ["src/core/lib/support/debug_location.h"],
     language = "c++",
+    public_hdrs = ["src/core/lib/support/debug_location.h"],
 )
 
 grpc_cc_library(
     name = "ref_counted",
-    public_hdrs = ["src/core/lib/support/ref_counted.h"],
     language = "c++",
+    public_hdrs = ["src/core/lib/support/ref_counted.h"],
     deps = [
-        "grpc_trace",
         "debug_location",
+        "grpc_trace",
     ],
 )
 
 grpc_cc_library(
     name = "ref_counted_ptr",
-    public_hdrs = ["src/core/lib/support/ref_counted_ptr.h"],
     language = "c++",
+    public_hdrs = ["src/core/lib/support/ref_counted_ptr.h"],
 )
 
 grpc_cc_library(
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 78ccfb2..8fd9483 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -525,6 +525,7 @@
 add_dependencies(buildtests_cxx cxx_time_test)
 add_dependencies(buildtests_cxx end2end_test)
 add_dependencies(buildtests_cxx error_details_test)
+add_dependencies(buildtests_cxx exception_test)
 add_dependencies(buildtests_cxx filter_end2end_test)
 add_dependencies(buildtests_cxx generic_end2end_test)
 add_dependencies(buildtests_cxx golden_file_test)
@@ -10179,6 +10180,46 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(exception_test
+  test/cpp/end2end/exception_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(exception_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(exception_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc++_test_util
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(filter_end2end_test
   test/cpp/end2end/filter_end2end_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
diff --git a/Makefile b/Makefile
index 875bbf1..8a38cc8 100644
--- a/Makefile
+++ b/Makefile
@@ -77,7 +77,6 @@
 CXX_opt = $(DEFAULT_CXX)
 LD_opt = $(DEFAULT_CC)
 LDXX_opt = $(DEFAULT_CXX)
-CXXFLAGS_opt = -fno-exceptions
 CPPFLAGS_opt = -O2
 DEFINES_opt = NDEBUG
 
@@ -95,7 +94,6 @@
 CXX_dbg = $(DEFAULT_CXX)
 LD_dbg = $(DEFAULT_CC)
 LDXX_dbg = $(DEFAULT_CXX)
-CXXFLAGS_dbg = -fno-exceptions
 CPPFLAGS_dbg = -O0
 DEFINES_dbg = _DEBUG DEBUG
 
@@ -144,14 +142,14 @@
 CPPFLAGS_asan-noleaks = -O0 -fsanitize-coverage=edge -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_asan-noleaks = -fsanitize=address
 
-VALID_CONFIG_c++-compat = 1
-CC_c++-compat = $(DEFAULT_CC)
-CXX_c++-compat = $(DEFAULT_CXX)
-LD_c++-compat = $(DEFAULT_CC)
-LDXX_c++-compat = $(DEFAULT_CXX)
-CFLAGS_c++-compat = -Wc++-compat
-CPPFLAGS_c++-compat = -O0
-DEFINES_c++-compat = _DEBUG DEBUG
+VALID_CONFIG_noexcept = 1
+CC_noexcept = $(DEFAULT_CC)
+CXX_noexcept = $(DEFAULT_CXX)
+LD_noexcept = $(DEFAULT_CC)
+LDXX_noexcept = $(DEFAULT_CXX)
+CXXFLAGS_noexcept = -fno-exceptions
+CPPFLAGS_noexcept = -O2
+DEFINES_noexcept = NDEBUG
 
 VALID_CONFIG_ubsan = 1
 REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
@@ -207,6 +205,15 @@
 CPPFLAGS_lto = -O2
 DEFINES_lto = NDEBUG
 
+VALID_CONFIG_c++-compat = 1
+CC_c++-compat = $(DEFAULT_CC)
+CXX_c++-compat = $(DEFAULT_CXX)
+LD_c++-compat = $(DEFAULT_CC)
+LDXX_c++-compat = $(DEFAULT_CXX)
+CFLAGS_c++-compat = -Wc++-compat
+CPPFLAGS_c++-compat = -O0
+DEFINES_c++-compat = _DEBUG DEBUG
+
 VALID_CONFIG_mutrace = 1
 CC_mutrace = $(DEFAULT_CC)
 CXX_mutrace = $(DEFAULT_CXX)
@@ -1124,6 +1131,7 @@
 cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
 end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
 error_details_test: $(BINDIR)/$(CONFIG)/error_details_test
+exception_test: $(BINDIR)/$(CONFIG)/exception_test
 filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
 golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
@@ -1572,6 +1580,7 @@
   $(BINDIR)/$(CONFIG)/cxx_time_test \
   $(BINDIR)/$(CONFIG)/end2end_test \
   $(BINDIR)/$(CONFIG)/error_details_test \
+  $(BINDIR)/$(CONFIG)/exception_test \
   $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
@@ -1702,6 +1711,7 @@
   $(BINDIR)/$(CONFIG)/cxx_time_test \
   $(BINDIR)/$(CONFIG)/end2end_test \
   $(BINDIR)/$(CONFIG)/error_details_test \
+  $(BINDIR)/$(CONFIG)/exception_test \
   $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
@@ -2102,6 +2112,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing error_details_test"
 	$(Q) $(BINDIR)/$(CONFIG)/error_details_test || ( echo test error_details_test failed ; exit 1 )
+	$(E) "[RUN]     Testing exception_test"
+	$(Q) $(BINDIR)/$(CONFIG)/exception_test || ( echo test exception_test failed ; exit 1 )
 	$(E) "[RUN]     Testing filter_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/filter_end2end_test || ( echo test filter_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing generic_end2end_test"
@@ -14974,6 +14986,49 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/util/error_details_test.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
 
 
+EXCEPTION_TEST_SRC = \
+    test/cpp/end2end/exception_test.cc \
+
+EXCEPTION_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(EXCEPTION_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/exception_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/exception_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/exception_test: $(PROTOBUF_DEP) $(EXCEPTION_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(EXCEPTION_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/exception_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/exception_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_exception_test: $(EXCEPTION_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(EXCEPTION_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 FILTER_END2END_TEST_SRC = \
     test/cpp/end2end/filter_end2end_test.cc \
 
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index 2560519..3d3f738 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -63,6 +63,10 @@
     defines = select({"//:grpc_no_ares": ["GRPC_ARES=0"],
                       "//conditions:default": [],}) +
               select({"//:remote_execution":  ["GRPC_PORT_ISOLATED_RUNTIME=1"],
+                      "//conditions:default": [],}) +
+              select({"//:grpc_allow_exceptions":  ["GRPC_ALLOW_EXCEPTIONS=1"],
+                      "//:grpc_disallow_exceptions":
+                      ["GRPC_ALLOW_EXCEPTIONS=0"],
                       "//conditions:default": [],}),
     hdrs = _maybe_update_cc_library_hdrs(hdrs + public_hdrs),
     deps = deps + _get_external_deps(external_deps),
diff --git a/build.yaml b/build.yaml
index db2ff88..c3d54f1 100644
--- a/build.yaml
+++ b/build.yaml
@@ -4007,6 +4007,19 @@
   deps:
   - grpc++_error_details
   - grpc++
+- name: exception_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/cpp/end2end/exception_test.cc
+  deps:
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: filter_end2end_test
   gtest: true
   build: test
@@ -4927,7 +4940,6 @@
     DEFINES: NDEBUG
   dbg:
     CPPFLAGS: -O0
-    CXXFLAGS: -fno-exceptions
     DEFINES: _DEBUG DEBUG
   gcov:
     CC: gcc
@@ -4968,10 +4980,13 @@
     CPPFLAGS: -O3 -fno-omit-frame-pointer
     DEFINES: NDEBUG
     LDFLAGS: -rdynamic
-  opt:
+  noexcept:
     CPPFLAGS: -O2
     CXXFLAGS: -fno-exceptions
     DEFINES: NDEBUG
+  opt:
+    CPPFLAGS: -O2
+    DEFINES: NDEBUG
   stapprof:
     CPPFLAGS: -O2 -DGRPC_STAP_PROFILER
     DEFINES: NDEBUG
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h
index c0af4ca..daf090f 100644
--- a/include/grpc++/impl/codegen/method_handler_impl.h
+++ b/include/grpc++/impl/codegen/method_handler_impl.h
@@ -27,6 +27,27 @@
 namespace grpc {
 
 namespace internal {
+
+// Invoke the method handler, fill in the status, and
+// return whether or not we finished safely (without an exception).
+// Note that exception handling is 0-cost in most compiler/library
+// implementations (except when an exception is actually thrown),
+// so this process doesn't require additional overhead in the common case.
+// Additionally, we don't need to return if we caught an exception or not;
+// the handling is the same in either case.
+template <class Callable>
+Status CatchingFunctionHandler(Callable&& handler) {
+#if GRPC_ALLOW_EXCEPTIONS
+  try {
+    return handler();
+  } catch (...) {
+    return Status(StatusCode::UNKNOWN, "Unexpected error in RPC handling");
+  }
+#else   // GRPC_ALLOW_EXCEPTIONS
+  return handler();
+#endif  // GRPC_ALLOW_EXCEPTIONS
+}
+
 /// A wrapper class of an application provided rpc method handler.
 template <class ServiceType, class RequestType, class ResponseType>
 class RpcMethodHandler : public MethodHandler {
@@ -43,7 +64,9 @@
         param.request.bbuf_ptr(), &req);
     ResponseType rsp;
     if (status.ok()) {
-      status = func_(service_, param.server_context, &req, &rsp);
+      status = CatchingFunctionHandler([this, &param, &req, &rsp] {
+        return func_(service_, param.server_context, &req, &rsp);
+      });
     }
 
     GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
@@ -86,7 +109,9 @@
   void RunHandler(const HandlerParameter& param) final {
     ServerReader<RequestType> reader(param.call, param.server_context);
     ResponseType rsp;
-    Status status = func_(service_, param.server_context, &reader, &rsp);
+    Status status = CatchingFunctionHandler([this, &param, &reader, &rsp] {
+      return func_(service_, param.server_context, &reader, &rsp);
+    });
 
     GPR_CODEGEN_ASSERT(!param.server_context->sent_initial_metadata_);
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
@@ -130,7 +155,9 @@
 
     if (status.ok()) {
       ServerWriter<ResponseType> writer(param.call, param.server_context);
-      status = func_(service_, param.server_context, &req, &writer);
+      status = CatchingFunctionHandler([this, &param, &req, &writer] {
+        return func_(service_, param.server_context, &req, &writer);
+      });
     }
 
     CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
@@ -172,7 +199,9 @@
 
   void RunHandler(const HandlerParameter& param) final {
     Streamer stream(param.call, param.server_context);
-    Status status = func_(param.server_context, &stream);
+    Status status = CatchingFunctionHandler([this, &param, &stream] {
+      return func_(param.server_context, &stream);
+    });
 
     CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
     if (!param.server_context->sent_initial_metadata_) {
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index ae1f951..819d17c 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -485,6 +485,21 @@
 #endif /* GPR_ATTRIBUTE_NO_TSAN (2) */
 #endif /* GPR_ATTRIBUTE_NO_TSAN (1) */
 
+/* GRPC_ALLOW_EXCEPTIONS should be 0 or 1 if exceptions are allowed or not */
+#ifndef GRPC_ALLOW_EXCEPTIONS
+/* If not already set, set to 1 on Windows (style guide standard) but to
+ * 0 on non-Windows platforms unless the compiler defines __EXCEPTIONS */
+#ifdef GPR_WINDOWS
+#define GRPC_ALLOW_EXCEPTIONS 1
+#else /* GPR_WINDOWS */
+#ifdef __EXCEPTIONS
+#define GRPC_ALLOW_EXCEPTIONS 1
+#else /* __EXCEPTIONS */
+#define GRPC_ALLOW_EXCEPTIONS 0
+#endif /* __EXCEPTIONS */
+#endif /* __GPR_WINDOWS */
+#endif /* GRPC_ALLOW_EXCEPTIONS */
+
 #ifndef __STDC_FORMAT_MACROS
 #define __STDC_FORMAT_MACROS
 #endif
diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc
index 6a3641f..6d7f898 100644
--- a/src/core/lib/security/transport/client_auth_filter.cc
+++ b/src/core/lib/security/transport/client_auth_filter.cc
@@ -114,7 +114,7 @@
     grpc_call_next_op(elem, batch);
   } else {
     error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
-                               GRPC_STATUS_UNAUTHENTICATED);
+                               GRPC_STATUS_UNAVAILABLE);
     grpc_transport_stream_op_batch_finish_with_failure(batch, error,
                                                        calld->call_combiner);
   }
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index a8cb357..4d695e8 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -27,7 +27,8 @@
 
     internal class NativeMetadataCredentialsPlugin
     {
-        const string GetMetadataExceptionMsg = "Exception occured in metadata credentials plugin.";
+        const string GetMetadataExceptionStatusMsg = "Exception occurred in metadata credentials plugin.";
+        const string GetMetadataExceptionLogMsg = GetMetadataExceptionStatusMsg + " This is likely not a problem with gRPC itself. Please verify that the code supplying the metadata (usually an authentication token) works correctly.";
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>();
         static readonly NativeMethods Native = NativeMethods.Get();
 
@@ -67,8 +68,8 @@
             }
             catch (Exception e)
             {
-                Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
-                Logger.Error(e, GetMetadataExceptionMsg);
+                Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionStatusMsg);
+                Logger.Error(e, GetMetadataExceptionLogMsg);
             }
         }
 
@@ -86,8 +87,8 @@
             }
             catch (Exception e)
             {
-                Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
-                Logger.Error(e, GetMetadataExceptionMsg);
+                Native.grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionStatusMsg);
+                Logger.Error(e, GetMetadataExceptionLogMsg);
             }
         }
     }
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index eba6276..c83ccd2 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -162,7 +162,7 @@
             client = new TestService.TestServiceClient(channel);
 
             var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { }));
-            Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
+            Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode);
         }
 
         private class FakeTestService : TestService.TestServiceBase
diff --git a/src/php/tests/unit_tests/CallCredentials2Test.php b/src/php/tests/unit_tests/CallCredentials2Test.php
index 0a58790..1c7e0c0 100644
--- a/src/php/tests/unit_tests/CallCredentials2Test.php
+++ b/src/php/tests/unit_tests/CallCredentials2Test.php
@@ -147,7 +147,7 @@
 
         $this->assertTrue($event->send_metadata);
         $this->assertTrue($event->send_close);
-        $this->assertTrue($event->status->code == Grpc\STATUS_UNAUTHENTICATED);
+        $this->assertTrue($event->status->code == Grpc\STATUS_UNAVAILABLE);
     }
 
     public function invalidReturnCallbackFunc($context)
@@ -179,6 +179,6 @@
 
         $this->assertTrue($event->send_metadata);
         $this->assertTrue($event->send_close);
-        $this->assertTrue($event->status->code == Grpc\STATUS_UNAUTHENTICATED);
+        $this->assertTrue($event->status->code == Grpc\STATUS_UNAVAILABLE);
     }
 }
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 79eeca9..5353b53 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -228,7 +228,7 @@
         th.join
       end
 
-      it 'should receive UNAUTHENTICATED if call credentials plugin fails' do
+      it 'should receive UNAVAILABLE if call credentials plugin fails' do
         server_port = create_secure_test_server
         th = run_request_response(@sent_msg, @resp, @pass)
 
@@ -252,7 +252,7 @@
         unauth_error_occured = false
         begin
           get_response(stub, credentials: creds)
-        rescue GRPC::Unauthenticated => e
+        rescue GRPC::Unavailable => e
           unauth_error_occured = true
           expect(e.details.include?(error_message)).to be true
         end
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
index fa77c30..8894c68 100644
--- a/test/cpp/end2end/BUILD
+++ b/test/cpp/end2end/BUILD
@@ -16,25 +16,31 @@
 
 load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package", "grpc_cc_binary")
 
-grpc_package(name = "test/cpp/end2end", visibility = "public") # Allows external users to implement end2end tests.
+grpc_package(
+    name = "test/cpp/end2end",
+    visibility = "public",
+)  # Allows external users to implement end2end tests.
 
 grpc_cc_library(
     name = "test_service_impl",
     testonly = True,
     srcs = ["test_service_impl.cc"],
     hdrs = ["test_service_impl.h"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//src/proto/grpc/testing:echo_proto",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "async_end2end_test",
     srcs = ["async_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -47,14 +53,17 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "client_crash_test",
     srcs = ["client_crash_test.cc"],
+    data = [
+        ":client_crash_test_server",
+    ],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -66,18 +75,16 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    data = [
-        ":client_crash_test_server",
-    ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_binary(
     name = "client_crash_test_server",
     testonly = True,
     srcs = ["client_crash_test_server.cc"],
+    external_deps = [
+        "gflags",
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -89,16 +96,15 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gflags",
-        "gtest",
-    ],
 )
 
 grpc_cc_library(
     name = "end2end_test_lib",
-    srcs = ["end2end_test.cc"],
     testonly = True,
+    srcs = ["end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         ":test_service_impl",
         "//:gpr",
@@ -111,21 +117,39 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "end2end_test",
     deps = [
-        ":end2end_test_lib"
+        ":end2end_test_lib",
+    ],
+)
+
+grpc_cc_test(
+    name = "exception_test",
+    srcs = ["exception_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//:grpc++",
+        "//src/proto/grpc/testing:echo_messages_proto",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+        "//test/cpp/util:test_util",
     ],
 )
 
 grpc_cc_test(
     name = "filter_end2end_test",
     srcs = ["filter_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -137,14 +161,14 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "generic_end2end_test",
     srcs = ["generic_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -156,14 +180,14 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "hybrid_end2end_test",
     srcs = ["hybrid_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         ":test_service_impl",
         "//:gpr",
@@ -176,14 +200,15 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "mock_test",
     srcs = ["mock_test.cc"],
+    external_deps = [
+        "gmock",
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -196,15 +221,14 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gmock",
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "client_lb_end2end_test",
     srcs = ["client_lb_end2end_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         ":test_service_impl",
         "//:gpr",
@@ -217,37 +241,38 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "grpclb_end2end_test",
     srcs = ["grpclb_end2end_test.cc"],
+    external_deps = [
+        "gmock",
+        "gtest",
+    ],
     deps = [
         ":test_service_impl",
         "//:gpr",
         "//:grpc",
         "//:grpc++",
+        "//:grpc_resolver_fake",
         "//src/proto/grpc/lb/v1:load_balancer_proto",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
-        "//:grpc_resolver_fake",
         "//test/core/util:gpr_test_util",
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gmock",
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "proto_server_reflection_test",
     srcs = ["proto_server_reflection_test.cc"],
+    external_deps = [
+        "gtest",
+        "gflags",
+    ],
     deps = [
         ":test_service_impl",
         "//:gpr",
@@ -262,15 +287,14 @@
         "//test/cpp/util:grpc++_proto_reflection_desc_db",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-        "gflags",
-    ],
 )
 
 grpc_cc_test(
     name = "server_builder_plugin_test",
     srcs = ["server_builder_plugin_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         ":test_service_impl",
         "//:gpr",
@@ -283,14 +307,17 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "server_crash_test",
     srcs = ["server_crash_test.cc"],
+    data = [
+        ":server_crash_test_client",
+    ],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -302,18 +329,16 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
-    data = [
-        ":server_crash_test_client",
-    ],
 )
 
 grpc_cc_binary(
     name = "server_crash_test_client",
     testonly = True,
     srcs = ["server_crash_test_client.cc"],
+    external_deps = [
+        "gflags",
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -325,15 +350,14 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gflags",
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "shutdown_test",
     srcs = ["shutdown_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -345,14 +369,14 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "streaming_throughput_test",
     srcs = ["streaming_throughput_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -364,14 +388,14 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
 
 grpc_cc_test(
     name = "thread_stress_test",
     srcs = ["thread_stress_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     deps = [
         "//:gpr",
         "//:grpc",
@@ -383,7 +407,4 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
-    external_deps = [
-        "gtest",
-    ],
 )
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 4c8dfe0..a6ea5aa 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -1609,7 +1609,7 @@
 
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_FALSE(s.ok());
-  EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
+  EXPECT_EQ(s.error_code(), StatusCode::UNAVAILABLE);
 }
 
 TEST_P(SecureEnd2endTest, AuthMetadataPluginValueFailure) {
@@ -1626,7 +1626,7 @@
 
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_FALSE(s.ok());
-  EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
+  EXPECT_EQ(s.error_code(), StatusCode::UNAVAILABLE);
 }
 
 TEST_P(SecureEnd2endTest, NonBlockingAuthMetadataPluginFailure) {
@@ -1644,7 +1644,7 @@
 
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_FALSE(s.ok());
-  EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
+  EXPECT_EQ(s.error_code(), StatusCode::UNAVAILABLE);
   EXPECT_EQ(s.error_message(),
             grpc::string("Getting metadata from plugin failed with error: ") +
                 kTestCredsPluginErrorMsg);
@@ -1705,7 +1705,7 @@
 
   Status s = stub_->Echo(&context, request, &response);
   EXPECT_FALSE(s.ok());
-  EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED);
+  EXPECT_EQ(s.error_code(), StatusCode::UNAVAILABLE);
   EXPECT_EQ(s.error_message(),
             grpc::string("Getting metadata from plugin failed with error: ") +
                 kTestCredsPluginErrorMsg);
diff --git a/test/cpp/end2end/exception_test.cc b/test/cpp/end2end/exception_test.cc
new file mode 100644
index 0000000..76272ad
--- /dev/null
+++ b/test/cpp/end2end/exception_test.cc
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <exception>
+#include <memory>
+
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc/impl/codegen/port_platform.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/test_config.h"
+
+#include <gtest/gtest.h>
+
+namespace grpc {
+namespace testing {
+
+const char* kErrorMessage = "This service caused an exception";
+
+#if GRPC_ALLOW_EXCEPTIONS
+class ExceptingServiceImpl : public ::grpc::testing::EchoTestService::Service {
+ public:
+  Status Echo(ServerContext* server_context, const EchoRequest* request,
+              EchoResponse* response) override {
+    throw - 1;
+  }
+  Status RequestStream(ServerContext* context,
+                       ServerReader<EchoRequest>* reader,
+                       EchoResponse* response) override {
+    throw ServiceException();
+  }
+
+ private:
+  class ServiceException final : public std::exception {
+   public:
+    ServiceException() {}
+
+   private:
+    const char* what() const noexcept override { return kErrorMessage; }
+  };
+};
+
+class ExceptionTest : public ::testing::Test {
+ protected:
+  ExceptionTest() {}
+
+  void SetUp() override {
+    ServerBuilder builder;
+    builder.RegisterService(&service_);
+    server_ = builder.BuildAndStart();
+  }
+
+  void TearDown() override { server_->Shutdown(); }
+
+  void ResetStub() {
+    channel_ = server_->InProcessChannel(ChannelArguments());
+    stub_ = grpc::testing::EchoTestService::NewStub(channel_);
+  }
+
+  std::shared_ptr<Channel> channel_;
+  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+  std::unique_ptr<Server> server_;
+  ExceptingServiceImpl service_;
+};
+
+TEST_F(ExceptionTest, Unary) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("test");
+  ClientContext context;
+
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_FALSE(s.ok());
+  EXPECT_EQ(s.error_code(), StatusCode::UNKNOWN);
+}
+
+TEST_F(ExceptionTest, RequestStream) {
+  ResetStub();
+  EchoResponse response;
+  ClientContext context;
+
+  auto stream = stub_->RequestStream(&context, &response);
+  stream->WritesDone();
+  Status s = stream->Finish();
+
+  EXPECT_FALSE(s.ok());
+  EXPECT_EQ(s.error_code(), StatusCode::UNKNOWN);
+}
+
+#endif  // GRPC_ALLOW_EXCEPTIONS
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tools/internal_ci/linux/grpc_interop_toprod.cfg b/tools/internal_ci/linux/grpc_interop_toprod.cfg
index 8d025c4..ff7a98f 100644
--- a/tools/internal_ci/linux/grpc_interop_toprod.cfg
+++ b/tools/internal_ci/linux/grpc_interop_toprod.cfg
@@ -26,5 +26,5 @@
 
 env_vars {
   key: "RUN_TESTS_FLAGS"
-  value: "-l all --cloud_to_prod --cloud_to_prod_auth --prod_servers default gateway_v4 --use_docker --internal_ci -t -j 12 --bq_result_table interop_results"
+  value: "-l all --cloud_to_prod --cloud_to_prod_auth --prod_servers default gateway_v4 cloud_gateway cloud_gateway_v4 --use_docker --internal_ci -t -j 12 --bq_result_table interop_results"
 }
diff --git a/tools/run_tests/generated/configs.json b/tools/run_tests/generated/configs.json
index fee8290..a14340c 100644
--- a/tools/run_tests/generated/configs.json
+++ b/tools/run_tests/generated/configs.json
@@ -42,7 +42,7 @@
     }
   }, 
   {
-    "config": "c++-compat"
+    "config": "noexcept"
   }, 
   {
     "config": "ubsan", 
@@ -74,6 +74,9 @@
     "config": "lto"
   }, 
   {
+    "config": "c++-compat"
+  }, 
+  {
     "config": "mutrace"
   }, 
   {
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 51f0ac7..c934155 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -3172,6 +3172,25 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c++", 
+    "name": "exception_test", 
+    "src": [
+      "test/cpp/end2end/exception_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
     "name": "filter_end2end_test", 
     "src": [
       "test/cpp/end2end/filter_end2end_test.cc"
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 6b83cec..afeee0b 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -3710,6 +3710,30 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "exception_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "filter_end2end_test", 
     "platforms": [
       "linux", 
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index ac90bef..3440354 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -313,6 +313,15 @@
         extra_envs={'GRPC_DNS_RESOLVER': 'ares'},
         timeout_seconds=_CPP_RUNTESTS_TIMEOUT)
 
+    # C and C++ with no-exceptions on Linux
+    test_jobs += _generate_jobs(
+        languages=['c', 'c++'],
+        configs=['noexcept'],
+        platforms=['linux'],
+        labels=['portability', 'corelang'],
+        extra_args=extra_args,
+        timeout_seconds=_CPP_RUNTESTS_TIMEOUT)
+
     # TODO(zyc): Turn on this test after adding c-ares support on windows.
     # C with the c-ares DNS resolver on Windows
     # test_jobs += _generate_jobs(languages=['c'],