1 /*
   2  * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "JavaTypes.h"
  27 #include "PlatformString.h"
  28 
  29 #include <list>
  30 
  31 
  32 #ifdef DEBUG
  33 TString JavaException::CreateExceptionMessage(JNIEnv* Env,
  34         jthrowable Exception, jmethodID GetCauseMethod,
  35         jmethodID GetStackTraceMethod, jmethodID ThrowableToTStringMethod,
  36         jmethodID FrameToTStringMethod) {
  37 
  38     TString result;
  39     jobjectArray frames =
  40             (jobjectArray)Env->CallObjectMethod(Exception, GetStackTraceMethod);
  41 
  42     // Append Throwable.toTString().
  43     if (0 != frames) {
  44         jstring jstr = (jstring)Env->CallObjectMethod(Exception,
  45                 ThrowableToTStringMethod);
  46         const char* str = Env->GetStringUTFChars(jstr, 0);
  47         result += PlatformString(str).toPlatformString();
  48         Env->ReleaseStringUTFChars(jstr, str);
  49         Env->DeleteLocalRef(jstr);
  50     }
  51 
  52     // Append stack trace if one exists.
  53     if (Env->GetArrayLength(frames) > 0) {
  54         jsize i = 0;
  55 
  56         for (i = 0; i < Env->GetArrayLength(frames); i++) {
  57             // Get the string from the next frame and append it to
  58             // the error message.
  59             jobject frame = Env->GetObjectArrayElement(frames, i);
  60             jstring obj = (jstring)Env->CallObjectMethod(frame,
  61                     FrameToTStringMethod);
  62             const char* str = Env->GetStringUTFChars(obj, 0);
  63             result += _T("\n  ");
  64             result += PlatformString(str).toPlatformString();
  65             Env->ReleaseStringUTFChars(obj, str);
  66             Env->DeleteLocalRef(obj);
  67             Env->DeleteLocalRef(frame);
  68         }
  69     }
  70 
  71     // If Exception has a cause then append the stack trace messages.
  72     if (0 != frames) {
  73         jthrowable cause =
  74                 (jthrowable)Env->CallObjectMethod(Exception, GetCauseMethod);
  75 
  76         if (cause != NULL) {
  77             result += CreateExceptionMessage(Env, cause, GetCauseMethod,
  78                 GetStackTraceMethod, ThrowableToTStringMethod,
  79                 FrameToTStringMethod);
  80         }
  81     }
  82 
  83     return result;
  84 }
  85 #endif //DEBUG
  86 
  87 JavaException::JavaException() : Exception() {}
  88 
  89 //#ifdef WINDOWS
  90 JavaException::JavaException(JNIEnv *Env,
  91         const TString Message) : Exception(Message) {
  92 //#endif //WINDOWS
  93 //#ifdef POSIX
  94 //JavaException::JavaException(JNIEnv *Env, TString message) {
  95 //#endif //POSIX
  96 
  97     FEnv = Env;
  98     FException = Env->ExceptionOccurred();
  99     Env->ExceptionClear();
 100 
 101 #ifdef DEBUG
 102     Platform& platform = Platform::GetInstance();
 103 
 104     if (platform.GetDebugState() == dsNone) {
 105         jclass ThrowableClass = Env->FindClass("java/lang/Throwable");
 106 
 107         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 108             Env->ExceptionClear();
 109             return;
 110         }
 111 
 112         jmethodID GetCauseMethod = Env->GetMethodID(ThrowableClass,
 113                 "getCause", "()Ljava/lang/Throwable;");
 114 
 115         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 116             Env->ExceptionClear();
 117             return;
 118         }
 119 
 120         jmethodID GetStackTraceMethod = Env->GetMethodID(ThrowableClass,
 121                  "getStackTrace", "()[Ljava/lang/StackTraceElement;");
 122 
 123         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 124             Env->ExceptionClear();
 125             return;
 126         }
 127 
 128         jmethodID ThrowableToTStringMethod = Env->GetMethodID(ThrowableClass,
 129                 "toString", "()Ljava/lang/String;");
 130 
 131         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 132             Env->ExceptionClear();
 133             return;
 134         }
 135 
 136         jclass FrameClass = Env->FindClass("java/lang/StackTraceElement");
 137 
 138         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 139             Env->ExceptionClear();
 140             return;
 141         }
 142 
 143         jmethodID FrameToTStringMethod = Env->GetMethodID(FrameClass,
 144                 "toString", "()Ljava/lang/String;");
 145 
 146         if (FEnv->ExceptionCheck() == JNI_TRUE) {
 147             Env->ExceptionClear();
 148             return;
 149         }
 150 
 151         TString lmessage = CreateExceptionMessage(Env, FException,
 152                 GetCauseMethod, GetStackTraceMethod, ThrowableToTStringMethod,
 153                 FrameToTStringMethod);
 154         SetMessage(lmessage);
 155     }
 156 #endif //DEBUG
 157 }
 158 
 159 void JavaException::Rethrow() {
 160     FEnv->Throw(FException);
 161 }