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
27 #include "ExceptionCheckingJniEnv.hpp"
28
29 namespace {
30
31 template<class T = void*>
32 class JNIVerifier {
33 public:
34 JNIVerifier(ExceptionCheckingJniEnv *env, const char* base_msg)
35 : _env(env), _base_msg(base_msg), _return_error(NULL) {
36 }
37
38 ~JNIVerifier() {
39 JNIEnv* jni_env = _env->GetJNIEnv();
40 if (jni_env->ExceptionCheck()) {
41 _env->HandleError(_base_msg);
42 return;
43 }
44
45 if (_return_error != NULL) {
46 ProcessReturnError();
47 }
48 }
49
50 void ProcessReturnError() {
51 int len = snprintf(NULL, 0, "%s : %s", _base_msg, _return_error) + 1;
52
53 if (len <= 0) {
54 _env->HandleError(_return_error);
55 return;
56 }
57
58 char* full_message = (char*) malloc(len);
59 if (full_message == NULL) {
60 _env->HandleError(_return_error);
61 return;
62 }
63
64 snprintf(full_message, len, "%s : %s", _base_msg, _return_error);
65
66 _env->HandleError(full_message);
67 free(full_message);
68 }
69
70 T ResultNotNull(T ptr) {
71 if (ptr == NULL) {
72 _return_error = "Return is NULL";
73 }
74 return ptr;
75 }
76
77 private:
78 ExceptionCheckingJniEnv* _env;
79 const char* const _base_msg;
80 const char* _return_error;
81 };
82
83 }
84
85 jclass ExceptionCheckingJniEnv::GetObjectClass(jobject obj) {
86 JNIVerifier<jclass> marker(this, "GetObjectClass");
87 return marker.ResultNotNull(_jni_env->GetObjectClass(obj));
88 }
89
90 jfieldID ExceptionCheckingJniEnv::GetFieldID(jclass klass, const char *name, const char* type) {
91 JNIVerifier<jfieldID> marker(this, "GetFieldID");
92 return marker.ResultNotNull(_jni_env->GetFieldID(klass, name, type));
93 }
94
95 jobject ExceptionCheckingJniEnv::GetObjectField(jobject obj, jfieldID field) {
96 JNIVerifier<jobject> marker(this, "GetObjectField");
97 return marker.ResultNotNull(_jni_env->GetObjectField(obj, field));
98 }
99
100 void ExceptionCheckingJniEnv::SetObjectField(jobject obj, jfieldID field, jobject value) {
101 JNIVerifier<> marker(this, "SetObjectField");
102 _jni_env->SetObjectField(obj, field, value);
103 }
104
105 jobject ExceptionCheckingJniEnv::NewGlobalRef(jobject obj) {
106 JNIVerifier<jobject> marker(this, "NewGlobalRef");
107 return marker.ResultNotNull(_jni_env->NewGlobalRef(obj));
108 }
109
110 void ExceptionCheckingJniEnv::DeleteGlobalRef(jobject obj) {
111 JNIVerifier<> marker(this, "DeleteGlobalRef");
112 _jni_env->DeleteGlobalRef(obj);
113 }
114
115 jobject ExceptionCheckingJniEnv::NewLocalRef(jobject obj) {
116 JNIVerifier<jobject> marker(this, "NewLocalRef");
117 return marker.ResultNotNull(_jni_env->NewLocalRef(obj));
118 }
119
120 void ExceptionCheckingJniEnv::DeleteLocalRef(jobject obj) {
121 JNIVerifier<> marker(this, "DeleteLocalRef");
122 _jni_env->DeleteLocalRef(obj);
123 }
124
125 jweak ExceptionCheckingJniEnv::NewWeakGlobalRef(jobject obj) {
126 JNIVerifier<jweak> marker(this, "NewWeakGlobalRef");
127 return marker.ResultNotNull(_jni_env->NewWeakGlobalRef(obj));
128 }
129
130 void ExceptionCheckingJniEnv::DeleteWeakGlobalRef(jweak weak_ref) {
131 JNIVerifier<> marker(this, "DeleteWeakGlobalRef");
132 _jni_env->DeleteWeakGlobalRef(weak_ref);
133 }
134
135 jsize ExceptionCheckingJniEnv::GetArrayLength(jarray array) {
136 JNIVerifier<> marker(this, "GetArrayLength");
137 return _jni_env->GetArrayLength(array);
138 }
139
140 jsize ExceptionCheckingJniEnv::GetStringLength(jstring str) {
141 JNIVerifier<> marker(this, "GetStringLength");
142 return _jni_env->GetStringLength(str);
143 }
144
145 void* ExceptionCheckingJniEnv::GetPrimitiveArrayCritical(jarray array, jboolean* isCopy) {
146 JNIVerifier<> marker(this, "GetPrimitiveArrayCritical");
147 return marker.ResultNotNull(_jni_env->GetPrimitiveArrayCritical(array, isCopy));
148 }
149
150 void ExceptionCheckingJniEnv::ReleasePrimitiveArrayCritical(jarray array, void* carray, jint mode) {
151 JNIVerifier<> marker(this, "ReleasePrimitiveArrayCritical");
152 _jni_env->ReleasePrimitiveArrayCritical(array, carray, mode);
153 }
154
155 const jchar* ExceptionCheckingJniEnv::GetStringCritical(jstring str, jboolean* isCopy) {
156 JNIVerifier<const jchar*> marker(this, "GetPrimitiveArrayCritical");
157 return marker.ResultNotNull(_jni_env->GetStringCritical(str, isCopy));
158 }
159
160 void ExceptionCheckingJniEnv::ReleaseStringCritical(jstring str, const jchar* carray) {
161 JNIVerifier<> marker(this, "ReleaseStringCritical");
162 _jni_env->ReleaseStringCritical(str, carray);
163 }
|
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* remove_folders(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(remove_folders(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(remove_folders(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(remove_folders(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(remove_folders(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 }
|