Merge pull request #12213 from dgquintas/v1.7.x-version-bump

Master version bump to 1.7.x
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index 6cd558d..a27284b 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -442,7 +442,7 @@
 
 end:
   BIO_free(bio);
-  if (x509 != NULL) X509_free(x509);
+  X509_free(x509);
   return result;
 }
 
@@ -496,6 +496,8 @@
   const grpc_json *key_prop;
   RSA *rsa = NULL;
   EVP_PKEY *result = NULL;
+  BIGNUM *tmp_n = NULL;
+  BIGNUM *tmp_e = NULL;
 
   GPR_ASSERT(kty != NULL && json != NULL);
   if (strcmp(kty, "RSA") != 0) {
@@ -507,8 +509,6 @@
     gpr_log(GPR_ERROR, "Could not create rsa key.");
     goto end;
   }
-  BIGNUM *tmp_n = NULL;
-  BIGNUM *tmp_e = NULL;
   for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) {
     if (strcmp(key_prop->key, "n") == 0) {
       tmp_n =
@@ -528,11 +528,16 @@
     gpr_log(GPR_ERROR, "Cannot set RSA key from inputs.");
     goto end;
   }
+  /* RSA_set0_key takes ownership on success. */
+  tmp_n = NULL;
+  tmp_e = NULL;
   result = EVP_PKEY_new();
   EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */
 
 end:
-  if (rsa != NULL) RSA_free(rsa);
+  RSA_free(rsa);
+  BN_free(tmp_n);
+  BN_free(tmp_e);
   return result;
 }
 
@@ -618,7 +623,7 @@
   result = 1;
 
 end:
-  if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
+  EVP_MD_CTX_destroy(md_ctx);
   return result;
 }
 
@@ -658,7 +663,7 @@
 
 end:
   if (json != NULL) grpc_json_destroy(json);
-  if (verification_key != NULL) EVP_PKEY_free(verification_key);
+  EVP_PKEY_free(verification_key);
   ctx->user_cb(exec_ctx, ctx->user_data, status, claims);
   verifier_cb_ctx_destroy(exec_ctx, ctx);
 }
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 89cf8ff..6fb6c41 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -99,9 +99,13 @@
       # event.  Send a status of deadline exceeded
       GRPC.logger.warn("late call: #{active_call}")
       send_status(active_call, DEADLINE_EXCEEDED, 'late')
-    rescue StandardError => e
+    rescue StandardError, NotImplementedError => e
       # This will usuaally be an unhandled error in the handling code.
       # Send back a UNKNOWN status to the client
+      #
+      # Note: this intentionally does not map NotImplementedError to
+      # UNIMPLEMENTED because NotImplementedError is intended for low-level
+      # OS interaction (e.g. syscalls) not supported by the current OS.
       GRPC.logger.warn("failed handler: #{active_call}; sending status:UNKNOWN")
       GRPC.logger.warn(e)
       send_status(active_call, UNKNOWN, "#{e.class}: #{e.message}")
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index be578c4..6852b98 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -52,6 +52,13 @@
       this_desc.run_server_method(@call, method(:other_error))
     end
 
+    it 'sends status UNKNOWN if NotImplementedErrors are raised' do
+      expect(@call).to receive(:read_unary_request).once.and_return(Object.new)
+      expect(@call).to receive(:send_status).once.with(
+        UNKNOWN, not_implemented_error_msg, false, metadata: {})
+      this_desc.run_server_method(@call, method(:not_implemented))
+    end
+
     it 'absorbs CallError with no further action' do
       expect(@call).to receive(:read_unary_request).once.and_raise(CallError)
       blk = proc do
@@ -102,6 +109,12 @@
         @client_streamer.run_server_method(@call, method(:other_error_alt))
       end
 
+      it 'sends status UNKNOWN if NotImplementedErrors are raised' do
+        expect(@call).to receive(:send_status).once.with(
+          UNKNOWN, not_implemented_error_msg, false, metadata: {})
+        @client_streamer.run_server_method(@call, method(:not_implemented_alt))
+      end
+
       it 'absorbs CallError with no further action' do
         expect(@call).to receive(:server_unary_response).once.and_raise(
           CallError)
@@ -166,6 +179,14 @@
         @bidi_streamer.run_server_method(@call, method(:other_error_alt))
       end
 
+      it 'sends status UNKNOWN if NotImplementedErrors are raised' do
+        expect(@call).to receive(:run_server_bidi).and_raise(
+          not_implemented_error)
+        expect(@call).to receive(:send_status).once.with(
+          UNKNOWN, not_implemented_error_msg, false, metadata: {})
+        @bidi_streamer.run_server_method(@call, method(:not_implemented_alt))
+      end
+
       it 'closes the stream if there no errors' do
         expect(@call).to receive(:run_server_bidi)
         expect(@call).to receive(:output_metadata).and_return(fake_md)
@@ -329,8 +350,25 @@
     fail(ArgumentError, 'other error')
   end
 
+  def not_implemented(_req, _call)
+    fail not_implemented_error
+  end
+
+  def not_implemented_alt(_call)
+    fail not_implemented_error
+  end
+
   def arg_error_msg(error = nil)
     error ||= ArgumentError.new('other error')
     "#{error.class}: #{error.message}"
   end
+
+  def not_implemented_error
+    NotImplementedError.new('some OS feature not implemented')
+  end
+
+  def not_implemented_error_msg(error = nil)
+    error ||= not_implemented_error
+    "#{error.class}: #{error.message}"
+  end
 end