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 + strncpy 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) + 1;
  64 
  65     size_t len = base_len + between_len + return_len;
  66 
  67     char* full_message = (char*) malloc(len);
  68     if (full_message == NULL) {
  69       _env->HandleError(_return_error);
  70       return;
  71     }
  72 
  73     // Now we construct the string using strcpy to not use sprintf/std::string
  74     // instead of:
  75     //     snprintf(full_message, len, "%s : %s", _base_msg, _return_error);
  76     strncpy(full_message, _base_msg, base_len);
  77     strncpy(full_message + base_len, between_msg, between_len);
  78     strncpy(full_message + base_len + between_len, _return_error, return_len);
  79     full_message[len] = '\0';
  80 
  81     // -1 due to the '\0' not counted by strlen but is counted for the allocation.
  82     if (strlen(full_message) != len - 1) {
  83       _env->GetJNIEnv()->FatalError("Length of message is not what was expected");
  84     }
  85 
  86     _env->HandleError(full_message);
  87     free(full_message);
  88   }
  89 
  90   T ResultNotNull(T ptr) {
  91     if (ptr == NULL) {
  92       _return_error = "Return is NULL";
  93     }
  94     return ptr;
  95   }
  96 
  97  private:
  98   ExceptionCheckingJniEnv* _env;
  99   const char* const _base_msg;
 100   const char* _return_error;
 101 };
 102 
 103 }
 104 
 105 jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj) {
 106   JNIVerifier<jclass> marker(this, "GetObjectClass");
 107   return marker.ResultNotNull(_jni_env->GetObjectClass(obj));
 108 }
 109 
 110 jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name, const char* type) {
 111   JNIVerifier<jfieldID> marker(this, "GetFieldID");
 112   return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type));
 113 }
 114 
 115 jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field) {
 116   JNIVerifier<jobject> marker(this, "GetObjectField");
 117   return marker.ResultNotNull(_jni_env->GetObjectField(obj, field));
 118 }
 119 
 120 void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value) {
 121   JNIVerifier<> marker(this, "SetObjectField");
 122   _jni_env->SetObjectField(obj, field, value);
 123 }
 124 
 125 jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj) {
 126   JNIVerifier<jobject> marker(this, "NewGlobalRef");
 127   return marker.ResultNotNull(_jni_env->NewGlobalRef(obj));
 128 }
 129 
 130 void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj) {
 131   JNIVerifier<> marker(this, "DeleteGlobalRef");
 132   _jni_env->DeleteGlobalRef(obj);
 133 }
 134 
 135 jobject ExceptionCheckingJniEnv::NewLocalRef(jobject obj) {
 136   JNIVerifier<jobject> marker(this, "NewLocalRef");
 137   return marker.ResultNotNull(_jni_env->NewLocalRef(obj));
 138 }
 139 
 140 void ExceptionCheckingJniEnv::DeleteLocalRef(jobject obj) {
 141   JNIVerifier<> marker(this, "DeleteLocalRef");
 142   _jni_env->DeleteLocalRef(obj);
 143 }
 144 
 145 jweak ExceptionCheckingJniEnv::NewWeakGlobalRef(jobject obj) {
 146   JNIVerifier<jweak> marker(this, "NewWeakGlobalRef");
 147   return marker.ResultNotNull(_jni_env->NewWeakGlobalRef(obj));
 148 }
 149 
 150 void ExceptionCheckingJniEnv::DeleteWeakGlobalRef(jweak weak_ref) {
 151   JNIVerifier<> marker(this, "DeleteWeakGlobalRef");
 152   _jni_env->DeleteWeakGlobalRef(weak_ref);
 153 }
 154 
 155 jsize ExceptionCheckingJniEnv::GetArrayLength(jarray array) {
 156   JNIVerifier<> marker(this, "GetArrayLength");
 157   return _jni_env->GetArrayLength(array);
 158 }
 159 
 160 jsize ExceptionCheckingJniEnv::GetStringLength(jstring str) {
 161   JNIVerifier<> marker(this, "GetStringLength");
 162   return _jni_env->GetStringLength(str);
 163 }
 164 
 165 void* ExceptionCheckingJniEnv::GetPrimitiveArrayCritical(jarray array, jboolean* isCopy) {
 166   JNIVerifier<> marker(this, "GetPrimitiveArrayCritical");
 167   return marker.ResultNotNull(_jni_env->GetPrimitiveArrayCritical(array, isCopy));
 168 }
 169 
 170 void ExceptionCheckingJniEnv::ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode) {
 171   JNIVerifier<> marker(this, "ReleasePrimitiveArrayCritical");
 172   _jni_env->ReleasePrimitiveArrayCritical(array, carray, mode);
 173 }
 174 
 175 const jchar* ExceptionCheckingJniEnv::GetStringCritical(jstring str, jboolean* isCopy) {
 176   JNIVerifier<const jchar*> marker(this, "GetPrimitiveArrayCritical");
 177   return marker.ResultNotNull(_jni_env->GetStringCritical(str, isCopy));
 178 }
 179 
 180 void ExceptionCheckingJniEnv::ReleaseStringCritical(jstring str, const jchar* carray) {
 181   JNIVerifier<> marker(this, "ReleaseStringCritical");
 182   _jni_env->ReleaseStringCritical(str, carray);
 183 }