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 #include <string.h>
  27 
  28 #include "ExceptionCheckingJniEnv.hpp"
  29 
  30 namespace {
  31 
  32 template<class T = void*>
  33 class JNIVerifier {
  34  public:
  35   JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg)
  36       : _env(env), _base_msg(base_msg), _return_error(NULL) {
  37   }
  38 
  39   ~JNIVerifier() {
  40     JNIEnv* jni_env = _env->GetJNIEnv();
  41     if (jni_env->ExceptionCheck()) {
  42       _env->HandleError(_base_msg);
  43       return;
  44     }
  45 
  46     if (_return_error != NULL) {
  47       ProcessReturnError();
  48     }
  49   }
  50 
  51   void ProcessReturnError() {
  52     // This is error prone, but:
  53     //   - Seems like we cannot use std::string (due to windows/solaris not
  54     //   building when used, seemingly due to exception libraries not linking).
  55     //   - Seems like we cannot use sprintf due to VS2013 (JDK-8213622).
  56     //
  57     //   We are aiming to do:
  58     //     snprintf(full_message, len, "%s : %s", _base_msg, _return_error);
  59     //   but will use strlen + memcpy instead.
  60     size_t base_len = strlen(_base_msg);
  61     const char* between_msg = " : ";
  62     size_t between_len = strlen(between_msg);
  63     size_t return_len = strlen(_return_error);
  64 
  65     // +1 for the '\0'
  66     size_t len = base_len + between_len + return_len + 1;
  67 
  68     char* full_message = (char*) malloc(len);
  69     if (full_message == NULL) {
  70       _env->HandleError(_return_error);
  71       return;
  72     }
  73 
  74     // Now we construct the string using memcpy to not use sprintf/std::string
  75     // instead of:
  76     //     snprintf(full_message, len, "%s : %s", _base_msg, _return_error);
  77     memcpy(full_message, _base_msg, base_len);
  78     memcpy(full_message + base_len, between_msg, between_len);
  79     memcpy(full_message + base_len + between_len, _return_error, return_len);
  80     full_message[len - 1] = '\0';
  81 
  82     // -1 due to the '\0' not counted by strlen but is counted for the allocation.
  83     if (strlen(full_message) != len - 1) {
  84       _env->GetJNIEnv()->FatalError("Length of message is not what was expected");
  85     }
  86 
  87     _env->HandleError(full_message);
  88     free(full_message);
  89   }
  90 
  91   T ResultNotNull(T ptr) {
  92     if (ptr == NULL) {
  93       _return_error = "Return is NULL";
  94     }
  95     return ptr;
  96   }
  97 
  98  private:
  99   ExceptionCheckingJniEnv* _env;
 100   const char* const _base_msg;
 101   const char* _return_error;
 102 };
 103 
 104 }
 105 
 106 jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj) {
 107   JNIVerifier<jclass> marker(this, "GetObjectClass");
 108   return marker.ResultNotNull(_jni_env->GetObjectClass(obj));
 109 }
 110 
 111 jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name, const char* type) {
 112   JNIVerifier<jfieldID> marker(this, "GetFieldID");
 113   return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type));
 114 }
 115 
 116 jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field) {
 117   JNIVerifier<jobject> marker(this, "GetObjectField");
 118   return marker.ResultNotNull(_jni_env->GetObjectField(obj, field));
 119 }
 120 
 121 void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value) {
 122   JNIVerifier<> marker(this, "SetObjectField");
 123   _jni_env->SetObjectField(obj, field, value);
 124 }
 125 
 126 jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj) {
 127   JNIVerifier<jobject> marker(this, "NewGlobalRef");
 128   return marker.ResultNotNull(_jni_env->NewGlobalRef(obj));
 129 }
 130 
 131 void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj) {
 132   JNIVerifier<> marker(this, "DeleteGlobalRef");
 133   _jni_env->DeleteGlobalRef(obj);
 134 }
 135 
 136 jobject ExceptionCheckingJniEnv::NewLocalRef(jobject obj) {
 137   JNIVerifier<jobject> marker(this, "NewLocalRef");
 138   return marker.ResultNotNull(_jni_env->NewLocalRef(obj));
 139 }
 140 
 141 void ExceptionCheckingJniEnv::DeleteLocalRef(jobject obj) {
 142   JNIVerifier<> marker(this, "DeleteLocalRef");
 143   _jni_env->DeleteLocalRef(obj);
 144 }
 145 
 146 jweak ExceptionCheckingJniEnv::NewWeakGlobalRef(jobject obj) {
 147   JNIVerifier<jweak> marker(this, "NewWeakGlobalRef");
 148   return marker.ResultNotNull(_jni_env->NewWeakGlobalRef(obj));
 149 }
 150 
 151 void ExceptionCheckingJniEnv::DeleteWeakGlobalRef(jweak weak_ref) {
 152   JNIVerifier<> marker(this, "DeleteWeakGlobalRef");
 153   _jni_env->DeleteWeakGlobalRef(weak_ref);
 154 }
 155 
 156 jsize ExceptionCheckingJniEnv::GetArrayLength(jarray array) {
 157   JNIVerifier<> marker(this, "GetArrayLength");
 158   return _jni_env->GetArrayLength(array);
 159 }
 160 
 161 jsize ExceptionCheckingJniEnv::GetStringLength(jstring str) {
 162   JNIVerifier<> marker(this, "GetStringLength");
 163   return _jni_env->GetStringLength(str);
 164 }
 165 
 166 void* ExceptionCheckingJniEnv::GetPrimitiveArrayCritical(jarray array, jboolean* isCopy) {
 167   JNIVerifier<> marker(this, "GetPrimitiveArrayCritical");
 168   return marker.ResultNotNull(_jni_env->GetPrimitiveArrayCritical(array, isCopy));
 169 }
 170 
 171 void ExceptionCheckingJniEnv::ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode) {
 172   JNIVerifier<> marker(this, "ReleasePrimitiveArrayCritical");
 173   _jni_env->ReleasePrimitiveArrayCritical(array, carray, mode);
 174 }
 175 
 176 const jchar* ExceptionCheckingJniEnv::GetStringCritical(jstring str, jboolean* isCopy) {
 177   JNIVerifier<const jchar*> marker(this, "GetPrimitiveArrayCritical");
 178   return marker.ResultNotNull(_jni_env->GetStringCritical(str, isCopy));
 179 }
 180 
 181 void ExceptionCheckingJniEnv::ReleaseStringCritical(jstring str, const jchar* carray) {
 182   JNIVerifier<> marker(this, "ReleaseStringCritical");
 183   _jni_env->ReleaseStringCritical(str, carray);
 184 }