rev 52828 : 8213501: Deploy ExceptionJniWrapper for a few tests
Summary:
Reviewed-by:

   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 #include <iostream>
  28 
  29 #include "ExceptionCheckingJniEnv.hpp"
  30 #include "nsk_tools.h"
  31 
  32 namespace {
  33 
  34 static const char* get_dirname(const char* fullname) {
  35   const char* p;
  36   const char* base = fullname;;
  37 
  38   if (fullname == NULL) {
  39     return NULL;
  40   }
  41 
  42   for (p = fullname; *p != '\0'; p++) {
  43     if (*p == '/' || *p == '\\') {
  44       base = p + 1;
  45     }
  46   }
  47   return base;
  48 }
  49 
  50 template<class T = void*>
  51 class JNIVerifier {
  52  public:
  53   JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_message,
  54               int line, const char* file)
  55       : _env(env), _base_message(base_message), _error_message(NULL),
  56         _line(line), _file(get_dirname(file)) {
  57   }
  58 
  59   // Until C++11 is supported, we have to write multiple template constructors.
  60   template <typename U>
  61   JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_message,
  62               U parameter,
  63               int line, const char* file)
  64       : _env(env), _base_message(base_message), _error_message(NULL),
  65         _line(line), _file(get_dirname(file)) {
  66           PrintPreCall(parameter);
  67   }
  68 
  69   template <typename U, typename V>
  70   JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_message,
  71               U parameter1,
  72               V parameter2,
  73               int line, const char* file)
  74       : _env(env), _base_message(base_message), _error_message(NULL),
  75         _line(line), _file(get_dirname(file)) {
  76           PrintPreCall(parameter1, parameter2);
  77   }
  78 
  79   template <typename U, typename V, typename W>
  80   JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_message,
  81               U parameter1, V parameter2, W parameter3,
  82               int line, const char* file)
  83       : _env(env), _base_message(base_message), _error_message(NULL),
  84         _line(line), _file(get_dirname(file)) {
  85           PrintPreCall(parameter1, parameter2, parameter3);
  86   }
  87 
  88   ~JNIVerifier() {
  89     PrintPostCall();
  90 
  91     JNIEnv* jni_env = _env->GetJNIEnv();
  92     if (jni_env->ExceptionCheck() && !_error_message) {
  93       _error_message = "internal error";
  94     }
  95 
  96     if (_error_message != NULL) {
  97       GenerateErrorMessage();
  98     }
  99   }
 100 
 101   int DecimalToAsciiRec(char *str, long line) {
 102     if (line == 0) {
 103       return 0;
 104     }
 105 
 106     int remainder = line % 10;
 107     long quotient = line / 10;
 108 
 109     int pos = DecimalToAsciiRec(str, quotient);
 110     str[pos] = '0' + remainder;
 111     return pos + 1;
 112   }
 113 
 114   // Implementing a simple version of sprintf for "%d"...
 115   void DecimalToAscii(char *str, int line) {
 116     // Go to long so that the INT_MIN case can be handled seemlessly.
 117     long internal_line = line;
 118     if (internal_line == 0) {
 119       str[0] = '0';
 120       str[1] = '\0';
 121       return;
 122     }
 123 
 124     if (internal_line < 0) {
 125       *str = '-';
 126       internal_line *= -1;
 127       str++;
 128     }
 129 
 130     str[DecimalToAsciiRec(str, internal_line)] = '\0';
 131   }
 132 
 133   void GenerateErrorMessage() {
 134     // This is error prone, but:
 135     //   - Seems like we cannot use std::string (due to windows/solaris not
 136     //   building when used, seemingly due to exception libraries not linking).
 137     //   - Seems like we cannot use sprintf due to VS2013 (JDK-8213622).
 138     //
 139     //   We are aiming to do:
 140     //     snprintf(full_message, len, "JNI method %s : %s from %s : %d", _base_message, _error_message,
 141     //              _file, _line);
 142     //   but will use strlen + memcpy instead.
 143     const char* pre_message = "JNI method ";
 144     const char* between_msg = " : ";
 145     const char* from_msg = " from ";
 146 
 147     const char* file_name = _file ? _file : "Unknown File";
 148     const char* strs[] = {
 149       pre_message,
 150       _base_message,
 151       between_msg,
 152       _error_message,
 153       from_msg,
 154       file_name,
 155       between_msg,
 156     };
 157 
 158     size_t msg_number = sizeof(strs) / sizeof(strs[0]);
 159     size_t len = 0;
 160     for (size_t i = 0; i < msg_number; i++) {
 161       len += strlen(strs[i]);
 162     }
 163 
 164     // 32-bit signed means 11 characters due to the '-'.
 165     const int MAX_INTEGER_DIGITS = 11;
 166     // Add for the line number and 1 for the '\0'.
 167     len += MAX_INTEGER_DIGITS + 1;
 168 
 169     char* full_message = (char*) malloc(len);
 170     if (full_message == NULL) {
 171       _env->HandleError(_error_message);
 172       return;
 173     }
 174 
 175     // Now we construct the string using strncat to not use sprintf/std::string
 176     // instead of:
 177     //     snprintf(full_message, len, "JNI method %s : %s from %s:%d", _base_message,
 178     //         _error_message, _file, _line);
 179     full_message[0] = '\0';
 180     size_t current_len = 0;
 181     for (size_t i = 0; i < msg_number; i++) {
 182       size_t current_src_len = strlen(strs[i]);
 183       current_len += current_src_len;
 184       if (current_len >= len) {
 185         _env->GetJNIEnv()->FatalError("Length of message is not what was expected");
 186       }
 187 
 188       strncat(full_message, strs[i], current_src_len);
 189     }
 190 
 191     // 10 is the max for an integer transformation.
 192     if (current_len + MAX_INTEGER_DIGITS >= len) {
 193       _env->GetJNIEnv()->FatalError("Length of message is not what was expected with line");
 194     }
 195 
 196     DecimalToAscii(full_message + current_len, _line);
 197 
 198     if (strlen(full_message) >= len) {
 199       _env->GetJNIEnv()->FatalError("Final length of message is not what was expected");
 200     }
 201 
 202     _env->HandleError(full_message);
 203     free(full_message);
 204   }
 205 
 206   T ResultNotNull(T ptr) {
 207     if (ptr == NULL) {
 208       _error_message = "Return is NULL";
 209     }
 210     return ptr;
 211   }
 212 
 213   T ResultIsZero(T value) {
 214     if (value != 0) {
 215       _error_message = "Return is not zero";
 216     }
 217     return value;
 218   }
 219 
 220   void PrintPreCallHeader() {
 221     if (!nsk_getVerboseMode()) {
 222       return;
 223     }
 224 
 225     std::cout << ">> Calling JNI method " << _base_message << " from " << _file
 226               << ":" << _line << std::endl;
 227     std::cout << ">> Calling with these parameter(s):" << std::endl;
 228   }
 229 
 230   // Until C++11 is supported, we have to write multiple PrintPreCall.
 231   template<class U>
 232   void PrintPreCall(U first_parameter) {
 233     if (!nsk_getVerboseMode()) {
 234       return;
 235     }
 236 
 237     PrintPreCallHeader();
 238     std::cout << "\t" << first_parameter << std::endl;
 239   }
 240 
 241   template<class U, class V>
 242   void PrintPreCall(U parameter1, V parameter2) {
 243     if (!nsk_getVerboseMode()) {
 244       return;
 245     }
 246 
 247     PrintPreCallHeader();
 248     std::cout << "\t" << parameter1 << std::endl;
 249     std::cout << "\t" << parameter2 << std::endl;
 250   }
 251 
 252   template<class U, class V, class W>
 253   void PrintPreCall(U parameter1, V parameter2, W parameter3) {
 254     if (!nsk_getVerboseMode()) {
 255       return;
 256     }
 257 
 258     PrintPreCallHeader();
 259     std::cout << "\t" << parameter1 << std::endl;
 260     std::cout << "\t" << parameter2 << std::endl;
 261     std::cout << "\t" << parameter3 << std::endl;
 262   }
 263 
 264   void PrintPostCall() {
 265     if (!nsk_getVerboseMode()) {
 266       return;
 267     }
 268 
 269     std::cout << "<< Called JNI method " << _base_message << " from " << _file
 270               << ":" << _line << std::endl;
 271   }
 272 
 273  private:
 274   ExceptionCheckingJniEnv* _env;
 275   const char* const _base_message;
 276   const char* _error_message;
 277   int _line;
 278   const char* const _file;
 279 };
 280 
 281 }
 282 
 283 jclass ExceptionCheckingJniEnv::FindClass(const char *class_name,
 284                                           int line, const char* file_name) {
 285   JNIVerifier<jclass> marker(this, "FindClass", class_name, line, file_name);
 286   return marker.ResultNotNull(_jni_env->FindClass(class_name));
 287 }
 288 
 289 jint ExceptionCheckingJniEnv::RegisterNatives(jclass clazz,
 290                                               const JNINativeMethod *methods,
 291                                               jint nMethods,
 292                                               int line,
 293                                               const char* file_name) {
 294   JNIVerifier<jint> marker(this, "RegisterNatives", methods, nMethods, line, file_name);
 295   return marker.ResultIsZero(_jni_env->RegisterNatives(clazz, methods, nMethods));
 296 }
 297 
 298 jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj, int line,
 299                                                const char* file_name) {
 300   JNIVerifier<jclass> marker(this, "GetObjectClass", obj, line, file_name);
 301   return marker.ResultNotNull(_jni_env->GetObjectClass(obj));
 302 }
 303 
 304 jfieldID ExceptionCheckingJniEnv::GetStaticFieldID(jclass klass, const char *name,
 305                                                    const char* type,
 306                                                    int line, const char* file_name) {
 307   JNIVerifier<jfieldID> marker(this, "GetStaticFieldID", klass, name, type,
 308                                line, file_name);
 309   return marker.ResultNotNull(_jni_env->GetStaticFieldID(klass, name, type));
 310 }
 311 
 312 jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name,
 313                                              const char* type,
 314                                              int line, const char* file_name) {
 315   JNIVerifier<jfieldID> marker(this, "GetFieldID", klass, name, type, line, file_name);
 316   return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type));
 317 }
 318 
 319 jobject ExceptionCheckingJniEnv::GetStaticObjectField(jclass klass, jfieldID field,
 320                                                       int line, const char* file_name) {
 321   JNIVerifier<jobject> marker(this, "GetStaticObjectField", klass, field,
 322                               line, file_name);
 323   return marker.ResultNotNull(_jni_env->GetStaticObjectField(klass, field));
 324 }
 325 
 326 jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field,
 327                                                 int line, const char* file_name) {
 328   JNIVerifier<jobject> marker(this, "GetObjectField", obj, field, line, file_name);
 329   return marker.ResultNotNull(_jni_env->GetObjectField(obj, field));
 330 }
 331 
 332 void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value,
 333                                              int line, const char* file_name) {
 334   JNIVerifier<> marker(this, "SetObjectField", obj, field, value, line, file_name);
 335   _jni_env->SetObjectField(obj, field, value);
 336 }
 337 
 338 jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj, int line, const char* file_name) {
 339   JNIVerifier<jobject> marker(this, "NewGlobalRef", obj, line, file_name);
 340   return marker.ResultNotNull(_jni_env->NewGlobalRef(obj));
 341 }
 342 
 343 void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj, int line, const char* file_name) {
 344   JNIVerifier<> marker(this, "DeleteGlobalRef", obj, line, file_name);
 345   _jni_env->DeleteGlobalRef(obj);
 346 }
 347 
 348 jobject ExceptionCheckingJniEnv::NewLocalRef(jobject obj, int line, const char* file_name) {
 349   JNIVerifier<jobject> marker(this, "NewLocalRef", obj, line, file_name);
 350   return marker.ResultNotNull(_jni_env->NewLocalRef(obj));
 351 }
 352 
 353 void ExceptionCheckingJniEnv::DeleteLocalRef(jobject obj, int line, const char* file_name) {
 354   JNIVerifier<> marker(this, "DeleteLocalRef", obj, line, file_name);
 355   _jni_env->DeleteLocalRef(obj);
 356 }
 357 
 358 jweak ExceptionCheckingJniEnv::NewWeakGlobalRef(jobject obj, int line, const char* file_name) {
 359   JNIVerifier<jweak> marker(this, "NewWeakGlobalRef", obj, line, file_name);
 360   return marker.ResultNotNull(_jni_env->NewWeakGlobalRef(obj));
 361 }
 362 
 363 void ExceptionCheckingJniEnv::DeleteWeakGlobalRef(jweak weak_ref, int line, const char* file_name) {
 364   JNIVerifier<> marker(this, "DeleteWeakGlobalRef", weak_ref, line, file_name);
 365   _jni_env->DeleteWeakGlobalRef(weak_ref);
 366 }
 367 
 368 jsize ExceptionCheckingJniEnv::GetArrayLength(jarray array, int line, const char* file_name) {
 369   JNIVerifier<> marker(this, "GetArrayLength", array, line, file_name);
 370   return _jni_env->GetArrayLength(array);
 371 }
 372 
 373 jsize ExceptionCheckingJniEnv::GetStringLength(jstring str, int line, const char* file_name) {
 374   JNIVerifier<> marker(this, "GetStringLength", str, line, file_name);
 375   return _jni_env->GetStringLength(str);
 376 }
 377 
 378 void* ExceptionCheckingJniEnv::GetPrimitiveArrayCritical(jarray array, jboolean* is_copy,
 379                                                          int line, const char* file_name) {
 380   JNIVerifier<> marker(this, "GetPrimitiveArrayCritical", array, is_copy, line, file_name);
 381   return marker.ResultNotNull(_jni_env->GetPrimitiveArrayCritical(array, is_copy));
 382 }
 383 
 384 void ExceptionCheckingJniEnv::ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode,
 385                                                             int line, const char* file_name) {
 386   JNIVerifier<> marker(this, "ReleasePrimitiveArrayCritical", array, carray, mode,
 387                        line, file_name);
 388   _jni_env->ReleasePrimitiveArrayCritical(array, carray, mode);
 389 }
 390 
 391 const jchar* ExceptionCheckingJniEnv::GetStringCritical(jstring str, jboolean* is_copy,
 392                                                         int line, const char* file_name) {
 393   JNIVerifier<const jchar*> marker(this, "GetPrimitiveArrayCritical", str, is_copy,
 394                                    line, file_name);
 395   return marker.ResultNotNull(_jni_env->GetStringCritical(str, is_copy));
 396 }
 397 
 398 void ExceptionCheckingJniEnv::ReleaseStringCritical(jstring str, const jchar* carray,
 399                                                     int line, const char* file_name) {
 400   JNIVerifier<> marker(this, "ReleaseStringCritical", str, carray, line, file_name);
 401   _jni_env->ReleaseStringCritical(str, carray);
 402 }
 403 
 404 jbyte* ExceptionCheckingJniEnv::GetByteArrayElements(jbyteArray array, jboolean* is_copy,
 405                                                    int line, const char* file_name) {
 406   JNIVerifier<jbyte*> marker(this, "GetByteArrayElements", array, is_copy, line, file_name);
 407   return marker.ResultNotNull(_jni_env->GetByteArrayElements(array, is_copy));
 408 }
 409 
 410 void ExceptionCheckingJniEnv::ReleaseByteArrayElements(jbyteArray array, jbyte* byte_array, jint mode,
 411                                                        int line, const char* file_name) {
 412   JNIVerifier<> marker(this, "ReleaseByteArrayElements", array, byte_array, mode,
 413                        line, file_name);
 414   _jni_env->ReleaseByteArrayElements(array, byte_array, mode);
 415 }
 416 
 417 jmethodID ExceptionCheckingJniEnv::GetMethodID(jclass klass, const char* name, const char* sig,
 418                                                int line, const char* file_name) {
 419   JNIVerifier<jmethodID> marker(this, "GetMethodID", klass, name, sig, line, file_name);
 420   return marker.ResultNotNull(_jni_env->GetMethodID(klass, name, sig));
 421 }
 422 
 423 jobject ExceptionCheckingJniEnv::NewObject(jclass klass, jmethodID methodID,
 424                                            int line, const char* file_name, ...) {
 425   // In the case of NewObject, we miss the extra arguments passed to NewObject sadly.
 426   JNIVerifier<jobject> marker(this, "NewObject", klass, methodID, line, file_name);
 427 
 428   va_list args;
 429   va_start(args, file_name);
 430   jobject result = marker.ResultNotNull(_jni_env->NewObjectV(klass, methodID, args));
 431   va_end(args);
 432   return result;
 433 }
--- EOF ---