1 /*
2  * Copyright (c) 2016, 2017, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include "jvmti.h"
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #ifndef JNI_ENV_ARG
33 
34 #ifdef __cplusplus
35 #define JNI_ENV_ARG(x, y) y
36 #define JNI_ENV_PTR(x) x
37 #else
38 #define JNI_ENV_ARG(x,y) x, y
39 #define JNI_ENV_PTR(x) (*x)
40 #endif
41 
42 #endif
43 
44 #define TranslateError(err) "JVMTI error"
45 
46 #define PASSED 0
47 #define FAILED 2
48 
49 static const char *EXC_CNAME = "java/lang/Exception";
50 static const char* MOD_CNAME = "Ljava/lang/Module;";
51 
52 static jvmtiEnv *jvmti = NULL;
53 static jint result = PASSED;
54 
55 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
56 
57 JNIEXPORT
Agent_OnLoad(JavaVM * jvm,char * options,void * reserved)58 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
59     return Agent_Initialize(jvm, options, reserved);
60 }
61 
62 JNIEXPORT
Agent_OnAttach(JavaVM * jvm,char * options,void * reserved)63 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
64     return Agent_Initialize(jvm, options, reserved);
65 }
66 
67 JNIEXPORT
JNI_OnLoad(JavaVM * jvm,void * reserved)68 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
69     return JNI_VERSION_1_8;
70 }
71 
72 static
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)73 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
74     jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
75                                         JVMTI_VERSION_9);
76     if (res != JNI_OK || jvmti == NULL) {
77         printf("    Error: wrong result of a valid call to GetEnv!\n");
78         return JNI_ERR;
79     }
80 
81     return JNI_OK;
82 }
83 
84 static
throw_exc(JNIEnv * env,char * msg)85 void throw_exc(JNIEnv *env, char *msg) {
86     jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
87     jint rt = JNI_OK;
88 
89     if (exc_class == NULL) {
90         printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
91         return;
92     }
93     rt = JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
94     if (rt == JNI_ERR) {
95         printf("throw_exc: Error in JNI ThrowNew(env, %s)\n", msg);
96     }
97 }
98 
99 static
jlM(JNIEnv * env)100 jclass jlM(JNIEnv *env) {
101     jclass cls = NULL;
102 
103     cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
104     if (cls == NULL) {
105         printf("    Error in JNI FindClass: %s\n", MOD_CNAME);
106     }
107     return cls;
108 }
109 
110 jmethodID
get_method(JNIEnv * env,jclass clazz,const char * name,const char * sig)111 get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
112     jmethodID method = NULL;
113 
114     method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
115     if (method == NULL) {
116         printf("    Error in JNI GetMethodID %s with signature %s", name, sig);
117     }
118     return method;
119 }
120 
121 static
can_use_service(JNIEnv * env,jobject module,jclass service)122 jboolean can_use_service(JNIEnv *env, jobject module, jclass service) {
123     static jmethodID mCanUse = NULL;
124     jboolean res = JNI_FALSE;
125 
126     if (mCanUse == NULL) {
127         const char* sign = "(Ljava/lang/Class;)Z";
128         mCanUse = get_method(env, jlM(env), "canUse", sign);
129     }
130     res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module),
131                                               mCanUse, service);
132     return res;
133 }
134 
135 JNIEXPORT jint JNICALL
Java_MyPackage_AddModuleUsesAndProvidesTest_checkUses(JNIEnv * env,jclass cls,jobject baseModule,jclass service)136 Java_MyPackage_AddModuleUsesAndProvidesTest_checkUses(JNIEnv *env,
137                                                       jclass  cls,
138                                                       jobject baseModule,
139                                                       jclass  service) {
140     jvmtiError err = JVMTI_ERROR_NONE;
141     jboolean used = JNI_FALSE;
142 
143     // Add a service to use to NULL module
144     printf("Check #UN1:\n");
145     err = (*jvmti)->AddModuleUses(jvmti, NULL, service);
146     if (err != JVMTI_ERROR_NULL_POINTER) {
147         printf("#UN1: jvmtiError from AddModuleUses: %d\n", err);
148         throw_exc(env, "Check #UN1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
149         return FAILED;
150     }
151 
152     // Add NULL service to use to baseModule
153     printf("Check #UN2:\n");
154     err = (*jvmti)->AddModuleUses(jvmti, baseModule, NULL);
155     if (err != JVMTI_ERROR_NULL_POINTER) {
156         printf("#UN2: jvmtiError from AddModuleUses: %d\n", err);
157         throw_exc(env, "Check #UN2: failed to return JVMTI_ERROR_NULL_POINTER for service==NULL");
158         return FAILED;
159     }
160 
161     // Add service to use to invalid module (cls)
162     printf("Check #UI1:\n");
163     err = (*jvmti)->AddModuleUses(jvmti, (jobject)cls, service);
164     if (err != JVMTI_ERROR_INVALID_MODULE) {
165         printf("#UI1: jvmtiError from AddModuleUses: %d\n", err);
166         throw_exc(env, "Check #UI1: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid module");
167         return FAILED;
168     }
169 
170     // Add invalid service (thisModule) to use to baseModule
171     printf("Check #UI2:\n");
172     err = (*jvmti)->AddModuleUses(jvmti, baseModule, baseModule);
173     if (err != JVMTI_ERROR_INVALID_CLASS) {
174         printf("#UI2: jvmtiError from AddModuleUses: %d\n", err);
175         throw_exc(env, "Check #UI2: did not get expected JVMTI_ERROR_INVALID_CLASS for invalid service");
176         return FAILED;
177     }
178 
179     // Check if the service can not be used
180     printf("Check #UC1:\n");
181     used = can_use_service(env, baseModule, service);
182     if (used != JNI_FALSE) {
183         throw_exc(env, "Check #UC1: unexpected use of service");
184         return FAILED;
185     }
186 
187     // Add uses of a correct service
188     printf("Check #UC2:\n");
189     err = (*jvmti)->AddModuleUses(jvmti, baseModule, service);
190     if (err != JVMTI_ERROR_NONE) {
191         printf("#UC2: jvmtiError from AddModuleUses: %d\n", err);
192         throw_exc(env, "Check #UC2: got unexpected JVMTI error");
193         return FAILED;
194     }
195 
196     // Check if the service can not be used
197     printf("Check #UC3:\n");
198     used = can_use_service(env, baseModule, service);
199     if (used == JNI_FALSE) {
200         throw_exc(env, "Check #UC3: service can not be used unexpectedly");
201         return FAILED;
202     }
203     fflush(0);
204     return PASSED;
205 }
206 
207 JNIEXPORT jint JNICALL
Java_MyPackage_AddModuleUsesAndProvidesTest_checkProvides(JNIEnv * env,jclass cls,jobject baseModule,jclass service,jclass serviceImpl)208 Java_MyPackage_AddModuleUsesAndProvidesTest_checkProvides(JNIEnv *env,
209                                                           jclass  cls,
210                                                           jobject baseModule,
211                                                           jclass  service,
212                                                           jclass  serviceImpl) {
213    jvmtiError err = JVMTI_ERROR_NONE;
214    jboolean provided = JNI_FALSE;
215 
216     // Add provides to NULL module
217     printf("Check #PN1:\n");
218     err = (*jvmti)->AddModuleProvides(jvmti, NULL, service, serviceImpl);
219     if (err != JVMTI_ERROR_NULL_POINTER) {
220         printf("#PN1: jvmtiError from AddModuleProvides: %d\n", err);
221         throw_exc(env, "Check #PN1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
222         return FAILED;
223     }
224 
225     // Add provides with NULL service
226     printf("Check #PN2:\n");
227     err = (*jvmti)->AddModuleProvides(jvmti, baseModule, NULL, serviceImpl);
228     if (err != JVMTI_ERROR_NULL_POINTER) {
229         printf("#PN2: jvmtiError from AddModuleProvides: %d\n", err);
230         throw_exc(env, "Check #PN2: failed to return JVMTI_ERROR_NULL_POINTER for service==NULL");
231         return FAILED;
232     }
233 
234     // Add provides with NULL serviceImpl
235     printf("Check #PN3:\n");
236     err = (*jvmti)->AddModuleProvides(jvmti, baseModule, service, NULL);
237     if (err != JVMTI_ERROR_NULL_POINTER) {
238         printf("#PN3: jvmtiError from AddModuleProvides: %d\n", err);
239         throw_exc(env, "Check #PN3: failed to return JVMTI_ERROR_NULL_POINTER for serviceImpl==NULL");
240         return FAILED;
241     }
242 
243     // Add provides to invalid module (cls)
244     printf("Check #PI1:\n");
245     err = (*jvmti)->AddModuleProvides(jvmti, (jobject)cls, service, serviceImpl);
246     if (err != JVMTI_ERROR_INVALID_MODULE) {
247         printf("#PI1: jvmtiError from AddModuleProvides: %d\n", err);
248         throw_exc(env, "Check #PI1: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid module");
249         return FAILED;
250     }
251 
252     // Add provides with invalid service (baseModule)
253     printf("Check #PI2:\n");
254     err = (*jvmti)->AddModuleProvides(jvmti, baseModule, baseModule, serviceImpl);
255     if (err != JVMTI_ERROR_INVALID_CLASS) {
256         printf("#PI2: jvmtiError from AddModuleProvides: %d\n", err);
257         throw_exc(env, "Check #PI2: did not get expected JVMTI_ERROR_INVALID_CLASS for invalid service");
258         return FAILED;
259     }
260 
261     // Add provides with invalid serviceImpl (baseModule)
262     printf("Check #PI3:\n");
263     err = (*jvmti)->AddModuleProvides(jvmti, baseModule, service, baseModule);
264     if (err != JVMTI_ERROR_INVALID_CLASS) {
265         printf("#PI3: jvmtiError from AddModuleProvides: %d\n", err);
266         throw_exc(env, "Check #PI3: did not get expected JVMTI_ERROR_INVALID_CLASS for invalid serviceImpl");
267         return FAILED;
268     }
269 
270     // Add provides to baseModule with correct service and serviceImpl
271     printf("Check #PC2:\n");
272     err = (*jvmti)->AddModuleProvides(jvmti, baseModule, service, serviceImpl);
273     if (err != JVMTI_ERROR_NONE) {
274         printf("#PC2: jvmtiError from AddModuleExports: %d\n", err);
275         throw_exc(env, "Check #PC2: error in add provides to baseModule with correct service and serviceImpl");
276         return FAILED;
277     }
278     fflush(0);
279     return PASSED;
280 }
281 
282 #ifdef __cplusplus
283 }
284 #endif
285