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 <iostream> 27 28 #include "ExceptionCheckingJniEnv.hpp" 29 #include "nsk_tools.h" 30 31 namespace { 32 33 static const char* get_basename(const char* fullname) { 34 const char* p; 35 const char* base = fullname;; 36 37 if (fullname == NULL) { 38 return NULL; 39 } 40 41 for (p = fullname; *p != '\0'; p++) { 42 if (*p == '/' || *p == '\\') { 43 base = p + 1; 44 } 45 } 46 return base; 47 } 48 49 template<class T = void*> 50 class JNIVerifier { 51 public: 52 JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg, 53 int line, const char* file) 54 : _env(env), _base_message(base_msg), _error_message(NULL), 55 _line(line), _file(get_basename(file)) { 56 } 57 58 // Until C++11 is supported, we have to write multiple template constructors. 59 template <typename U> 60 JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg, 61 U parameter, 62 int line, const char* file) 63 : _env(env), _base_message(base_msg), _error_message(NULL), 64 _line(line), _file(get_basename(file)) { 65 PrintPreCall(parameter); 66 } 67 68 template <typename U, typename V> 69 JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg, 70 U parameter1, 71 V parameter2, 72 int line, const char* file) 73 : _env(env), _base_message(base_msg), _error_message(NULL), 74 _line(line), _file(get_basename(file)) { 75 PrintPreCall(parameter1, parameter2); 76 } 77 78 template <typename U, typename V, typename W> 79 JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg, 80 U parameter1, V parameter2, W parameter3, 81 int line, const char* file) 82 : _env(env), _base_message(base_msg), _error_message(NULL), 83 _line(line), _file(get_basename(file)) { 84 PrintPreCall(parameter1, parameter2, parameter3); 85 } 86 87 ~JNIVerifier() { 88 PrintPostCall(); 89 90 JNIEnv* jni_env = _env->GetJNIEnv(); 91 if (jni_env->ExceptionCheck()) { 92 _error_message = "internal error"; 93 } 94 95 if (_error_message != NULL) { 96 GenerateErrorMessage(); 97 } 98 } 99 100 void GenerateErrorMessage() { 101 int len = snprintf(NULL, 0, "JNI method %s : %s from %s:%d", _base_message, _error_message, 102 _file, _line) + 1; 103 104 if (len <= 0) { 105 _env->HandleError(_error_message); 106 return; 107 } 108 109 char* full_message = (char*) malloc(len); 110 if (full_message == NULL) { 111 _env->HandleError(_error_message); 112 return; 113 } 114 115 snprintf(full_message, len, "JNI method %s : %s from %s:%d", _base_message, _error_message, 116 _file, _line); 117 118 _env->HandleError(full_message); 119 free(full_message); 120 } 121 122 T ResultNotNull(T ptr) { 123 if (ptr == NULL) { 124 _error_message = "Return is NULL"; 125 } 126 return ptr; 127 } 128 129 T ResultIsZero(T value) { 130 if (value != 0) { 131 _error_message = "Return is not zero"; 132 } 133 return value; 134 } 135 136 void PrintPreCallHeader() { 137 if (!nsk_getVerboseMode()) { 138 return; 139 } 140 141 std::cout << ">> Calling JNI method " << _base_message << " from " << _file 142 << ":" << _line << std::endl; 143 std::cout << ">> Calling with these parameter(s):" << std::endl; 144 } 145 146 // Until C++11 is supported, we have to write multiple PrintPreCall. 147 template<class U> 148 void PrintPreCall(U first_parameter) { 149 if (!nsk_getVerboseMode()) { 150 return; 151 } 152 153 PrintPreCallHeader(); 154 std::cout << "\t" << first_parameter << std::endl; 155 } 156 157 template<class U, class V> 158 void PrintPreCall(U parameter1, V parameter2) { 159 if (!nsk_getVerboseMode()) { 160 return; 161 } 162 163 PrintPreCallHeader(); 164 std::cout << "\t" << parameter1 << std::endl; 165 std::cout << "\t" << parameter2 << std::endl; 166 } 167 168 template<class U, class V, class W> 169 void PrintPreCall(U parameter1, V parameter2, W parameter3) { 170 if (!nsk_getVerboseMode()) { 171 return; 172 } 173 174 PrintPreCallHeader(); 175 std::cout << "\t" << parameter1 << std::endl; 176 std::cout << "\t" << parameter2 << std::endl; 177 std::cout << "\t" << parameter3 << std::endl; 178 } 179 180 void PrintPostCall() { 181 if (!nsk_getVerboseMode()) { 182 return; 183 } 184 185 std::cout << "<< Called JNI method " << _base_message << " from " << _file 186 << ":" << _line << std::endl; 187 } 188 189 private: 190 ExceptionCheckingJniEnv* _env; 191 const char* const _base_message; 192 const char* _error_message; 193 int _line; 194 const char* const _file; 195 }; 196 197 } 198 199 jclass ExceptionCheckingJniEnv::FindClass(const char *class_name, 200 int line, const char* file_name) { 201 JNIVerifier<jclass> marker(this, "FindClass", class_name, line, file_name); 202 return marker.ResultNotNull(_jni_env->FindClass(class_name)); 203 } 204 205 jint ExceptionCheckingJniEnv::RegisterNatives(jclass clazz, 206 const JNINativeMethod *methods, 207 jint nMethods, 208 int line, 209 const char* file_name) { 210 JNIVerifier<jint> marker(this, "RegisterNatives", methods, nMethods, line, file_name); 211 return marker.ResultIsZero(_jni_env->RegisterNatives(clazz, methods, nMethods)); 212 } 213 214 jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj, int line, 215 const char* file_name) { 216 JNIVerifier<jclass> marker(this, "GetObjectClass", obj, line, file_name); 217 return marker.ResultNotNull(_jni_env->GetObjectClass(obj)); 218 } 219 220 jfieldID ExceptionCheckingJniEnv::GetStaticFieldID(jclass klass, const char *name, 221 const char* type, 222 int line, const char* file_name) { 223 JNIVerifier<jfieldID> marker(this, "GetStaticFieldID", klass, name, type, 224 line, file_name); 225 return marker.ResultNotNull(_jni_env->GetStaticFieldID(klass, name, type)); 226 } 227 228 jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name, 229 const char* type, 230 int line, const char* file_name) { 231 JNIVerifier<jfieldID> marker(this, "GetFieldID", klass, name, type, line, file_name); 232 return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type)); 233 } 234 235 jobject ExceptionCheckingJniEnv::GetStaticObjectField(jclass klass, jfieldID field, 236 int line, const char* file_name) { 237 JNIVerifier<jobject> marker(this, "GetStaticObjectField", klass, field, 238 line, file_name); 239 return marker.ResultNotNull(_jni_env->GetStaticObjectField(klass, field)); 240 } 241 242 jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field, 243 int line, const char* file_name) { 244 JNIVerifier<jobject> marker(this, "GetObjectField", obj, field, line, file_name); 245 return marker.ResultNotNull(_jni_env->GetObjectField(obj, field)); 246 } 247 248 void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value, 249 int line, const char* file_name) { 250 JNIVerifier<> marker(this, "SetObjectField", obj, field, value, line, file_name); 251 _jni_env->SetObjectField(obj, field, value); 252 } 253 254 jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj, int line, const char* file_name) { 255 JNIVerifier<jobject> marker(this, "NewGlobalRef", obj, line, file_name); 256 return marker.ResultNotNull(_jni_env->NewGlobalRef(obj)); 257 } 258 259 void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj, int line, const char* file_name) { 260 JNIVerifier<> marker(this, "DeleteGlobalRef", obj, line, file_name); 261 _jni_env->DeleteGlobalRef(obj); 262 } 263 264 jobject ExceptionCheckingJniEnv::NewLocalRef(jobject obj, int line, const char* file_name) { 265 JNIVerifier<jobject> marker(this, "NewLocalRef", obj, line, file_name); 266 return marker.ResultNotNull(_jni_env->NewLocalRef(obj)); 267 } 268 269 void ExceptionCheckingJniEnv::DeleteLocalRef(jobject obj, int line, const char* file_name) { 270 JNIVerifier<> marker(this, "DeleteLocalRef", obj, line, file_name); 271 _jni_env->DeleteLocalRef(obj); 272 } 273 274 jweak ExceptionCheckingJniEnv::NewWeakGlobalRef(jobject obj, int line, const char* file_name) { 275 JNIVerifier<jweak> marker(this, "NewWeakGlobalRef", obj, line, file_name); 276 return marker.ResultNotNull(_jni_env->NewWeakGlobalRef(obj)); 277 } 278 279 void ExceptionCheckingJniEnv::DeleteWeakGlobalRef(jweak weak_ref, int line, const char* file_name) { 280 JNIVerifier<> marker(this, "DeleteWeakGlobalRef", weak_ref, line, file_name); 281 _jni_env->DeleteWeakGlobalRef(weak_ref); 282 } 283 284 jsize ExceptionCheckingJniEnv::GetArrayLength(jarray array, int line, const char* file_name) { 285 JNIVerifier<> marker(this, "GetArrayLength", array, line, file_name); 286 return _jni_env->GetArrayLength(array); 287 } 288 289 jsize ExceptionCheckingJniEnv::GetStringLength(jstring str, int line, const char* file_name) { 290 JNIVerifier<> marker(this, "GetStringLength", str, line, file_name); 291 return _jni_env->GetStringLength(str); 292 } 293 294 void* ExceptionCheckingJniEnv::GetPrimitiveArrayCritical(jarray array, jboolean* is_copy, 295 int line, const char* file_name) { 296 JNIVerifier<> marker(this, "GetPrimitiveArrayCritical", array, is_copy, line, file_name); 297 return marker.ResultNotNull(_jni_env->GetPrimitiveArrayCritical(array, is_copy)); 298 } 299 300 void ExceptionCheckingJniEnv::ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode, 301 int line, const char* file_name) { 302 JNIVerifier<> marker(this, "ReleasePrimitiveArrayCritical", array, carray, mode, 303 line, file_name); 304 _jni_env->ReleasePrimitiveArrayCritical(array, carray, mode); 305 } 306 307 const jchar* ExceptionCheckingJniEnv::GetStringCritical(jstring str, jboolean* is_copy, 308 int line, const char* file_name) { 309 JNIVerifier<const jchar*> marker(this, "GetPrimitiveArrayCritical", str, is_copy, 310 line, file_name); 311 return marker.ResultNotNull(_jni_env->GetStringCritical(str, is_copy)); 312 } 313 314 void ExceptionCheckingJniEnv::ReleaseStringCritical(jstring str, const jchar* carray, 315 int line, const char* file_name) { 316 JNIVerifier<> marker(this, "ReleaseStringCritical", str, carray, line, file_name); 317 _jni_env->ReleaseStringCritical(str, carray); 318 } 319 320 jbyte* ExceptionCheckingJniEnv::GetByteArrayElements(jbyteArray array, jboolean* is_copy, 321 int line, const char* file_name) { 322 JNIVerifier<jbyte*> marker(this, "GetByteArrayElements", array, is_copy, line, file_name); 323 return marker.ResultNotNull(_jni_env->GetByteArrayElements(array, is_copy)); 324 } 325 326 void ExceptionCheckingJniEnv::ReleaseByteArrayElements(jbyteArray array, jbyte* byte_array, jint mode, 327 int line, const char* file_name) { 328 JNIVerifier<> marker(this, "ReleaseByteArrayElements", array, byte_array, mode, 329 line, file_name); 330 _jni_env->ReleaseByteArrayElements(array, byte_array, mode); 331 } 332 333 jmethodID ExceptionCheckingJniEnv::GetMethodID(jclass klass, const char* name, const char* sig, 334 int line, const char* file_name) { 335 JNIVerifier<jmethodID> marker(this, "GetMethodID", klass, name, sig, line, file_name); 336 return marker.ResultNotNull(_jni_env->GetMethodID(klass, name, sig)); 337 } 338 339 jobject ExceptionCheckingJniEnv::NewObject(jclass klass, jmethodID methodID, 340 int line, const char* file_name, ...) { 341 // In the case of NewObject, we miss the extra arguments passed to NewObject sadly. 342 JNIVerifier<jobject> marker(this, "NewObject", klass, methodID, line, file_name); 343 344 va_list args; 345 va_start(args, file_name); 346 jobject result = marker.ResultNotNull(_jni_env->NewObjectV(klass, methodID, args)); 347 va_end(args); 348 return result; 349 }