1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, Google and/or its affiliates. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 #include <stdlib.h>
  26 
  27 #include "ExceptionCheckingJniEnv.hpp"
  28 
  29 namespace {
  30 
  31 template<class T = void*>
  32 class JNIVerifier {
  33  public:
  34   JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg)
  35       : _env(env), _base_msg(base_msg), _return_error(NULL) {
  36   }
  37 
  38   ~JNIVerifier() {
  39     JNIEnv* jni_env = _env->GetJNIEnv();
  40     if (jni_env->ExceptionCheck()) {
  41       _env->HandleError(_base_msg);
  42       return;
  43     }
  44 
  45     if (_return_error != NULL) {
  46       ProcessReturnError();
  47     }
  48   }
  49 
  50   void ProcessReturnError() {
  51     int len = snprintf(NULL, 0, "%s : %s", _base_msg, _return_error) + 1;
  52 
  53     if (len <= 0) {
  54       _env->HandleError(_return_error);
  55       return;
  56     }
  57 
  58     char* full_message = (char*) malloc(len);
  59     if (full_message == NULL) {
  60       _env->HandleError(_return_error);
  61       return;
  62     }
  63 
  64     snprintf(full_message, len, "%s : %s", _base_msg, _return_error);
  65 
  66     _env->HandleError(full_message);
  67     free(full_message);
  68   }
  69 
  70   T ResultNotNull(T ptr) {
  71     if (ptr == NULL) {
  72       _return_error = "Return is NULL";
  73     }
  74     return ptr;
  75   }
  76 
  77  private:
  78   ExceptionCheckingJniEnv* _env;
  79   const char* const _base_msg;
  80   const char* _return_error;
  81 };
  82 
  83 }
  84 
  85 jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj) {
  86   JNIVerifier<jclass> marker(this, "GetObjectClass");
  87   return marker.ResultNotNull(_jni_env->GetObjectClass(obj));
  88 }
  89 
  90 jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name, const char* type) {
  91   JNIVerifier<jfieldID> marker(this, "GetFieldID");
  92   return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type));
  93 }
  94 
  95 jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field) {
  96   JNIVerifier<jobject> marker(this, "GetObjectField");
  97   return marker.ResultNotNull(_jni_env->GetObjectField(obj, field));
  98 }
  99 
 100 void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value) {
 101   JNIVerifier<> marker(this, "SetObjectField");
 102   _jni_env->SetObjectField(obj, field, value);
 103 }
 104 
 105 jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj) {
 106   JNIVerifier<jobject> marker(this, "NewGlobalRef");
 107   return marker.ResultNotNull(_jni_env->NewGlobalRef(obj));
 108 }
 109 
 110 void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj) {
 111   JNIVerifier<> marker(this, "DeleteGlobalRef");
 112   _jni_env->DeleteGlobalRef(obj);
 113 }
 114 
 115 jobject ExceptionCheckingJniEnv::NewLocalRef(jobject obj) {
 116   JNIVerifier<jobject> marker(this, "NewLocalRef");
 117   return marker.ResultNotNull(_jni_env->NewLocalRef(obj));
 118 }
 119 
 120 void ExceptionCheckingJniEnv::DeleteLocalRef(jobject obj) {
 121   JNIVerifier<> marker(this, "DeleteLocalRef");
 122   _jni_env->DeleteLocalRef(obj);
 123 }
 124 
 125 jweak ExceptionCheckingJniEnv::NewWeakGlobalRef(jobject obj) {
 126   JNIVerifier<jweak> marker(this, "NewWeakGlobalRef");
 127   return marker.ResultNotNull(_jni_env->NewWeakGlobalRef(obj));
 128 }
 129 
 130 void ExceptionCheckingJniEnv::DeleteWeakGlobalRef(jweak weak_ref) {
 131   JNIVerifier<> marker(this, "DeleteWeakGlobalRef");
 132   _jni_env->DeleteWeakGlobalRef(weak_ref);
 133 }
 134 
 135 jsize ExceptionCheckingJniEnv::GetArrayLength(jarray array) {
 136   JNIVerifier<> marker(this, "GetArrayLength");
 137   return _jni_env->GetArrayLength(array);
 138 }
 139 
 140 jsize ExceptionCheckingJniEnv::GetStringLength(jstring str) {
 141   JNIVerifier<> marker(this, "GetStringLength");
 142   return _jni_env->GetStringLength(str);
 143 }
 144 
 145 void* ExceptionCheckingJniEnv::GetPrimitiveArrayCritical(jarray array, jboolean* isCopy) {
 146   JNIVerifier<> marker(this, "GetPrimitiveArrayCritical");
 147   return marker.ResultNotNull(_jni_env->GetPrimitiveArrayCritical(array, isCopy));
 148 }
 149 
 150 void ExceptionCheckingJniEnv::ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode) {
 151   JNIVerifier<> marker(this, "ReleasePrimitiveArrayCritical");
 152   _jni_env->ReleasePrimitiveArrayCritical(array, carray, mode);
 153 }
 154 
 155 const jchar* ExceptionCheckingJniEnv::GetStringCritical(jstring str, jboolean* isCopy) {
 156   JNIVerifier<const jchar*> marker(this, "GetPrimitiveArrayCritical");
 157   return marker.ResultNotNull(_jni_env->GetStringCritical(str, isCopy));
 158 }
 159 
 160 void ExceptionCheckingJniEnv::ReleaseStringCritical(jstring str, const jchar* carray) {
 161   JNIVerifier<> marker(this, "ReleaseStringCritical");
 162   _jni_env->ReleaseStringCritical(str, carray);
 163 }