libAddModuleReadsTest.c revision 12290:8953c0318163
1/*
2 * Copyright (c) 2016, 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
29extern "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
49static const char *EXC_CNAME = "java/lang/Exception";
50static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
51
52static jvmtiEnv *jvmti = NULL;
53static jint result = PASSED;
54
55static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
56
57JNIEXPORT
58jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
59    return Agent_Initialize(jvm, options, reserved);
60}
61
62JNIEXPORT
63jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
64    return Agent_Initialize(jvm, options, reserved);
65}
66
67JNIEXPORT
68jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
69    return JNI_VERSION_1_8;
70}
71
72static
73jint 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    return JNI_OK;
81}
82
83static
84jint throw_exc(JNIEnv *env, char *msg) {
85    jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
86
87    if (exc_class == NULL) {
88        printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
89        return -1;
90    }
91    return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
92}
93
94static
95jclass jlrM(JNIEnv *env) {
96    jclass cls = NULL;
97
98    cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
99    if (cls == NULL) {
100        printf("    Error in JNI FindClass: %s\n", MOD_CNAME);
101    }
102    return cls;
103}
104
105jmethodID
106get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
107    jmethodID method = NULL;
108
109    method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
110    if (method == NULL) {
111        printf("    Error in JNI GetMethodID %s with signature %s", name, sig);
112    }
113    return method;
114}
115
116static
117jboolean can_module_read(JNIEnv *env, jobject module, jobject to_module) {
118    static jmethodID mCanRead = NULL;
119    jboolean res = JNI_FALSE;
120
121    if (mCanRead == NULL) {
122        const char* sign = "(Ljava/lang/reflect/Module;)Z";
123        mCanRead = get_method(env, jlrM(env), "canRead", sign);
124    }
125    res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module),
126                                              mCanRead, to_module);
127    return res;
128}
129
130static
131jint check_add_module_reads(JNIEnv *env,
132                            jclass  cls,
133                            jobject unnamedModule,
134                            jobject baseModule,
135                            jobject instrModule) {
136    jvmtiError err = JVMTI_ERROR_NONE;
137    jboolean can = JNI_FALSE;
138
139    // Add an invalid read edge from NULL module
140    printf("Check #N1:\n");
141    err = (*jvmti)->AddModuleReads(jvmti, NULL, baseModule);
142    if (err != JVMTI_ERROR_NULL_POINTER) {
143        printf("#N1: jvmtiError from AddModuleReads: %d\n", err);
144        throw_exc(env, "Check #N1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL");
145        return FAILED;
146    }
147
148    // Add an invalid read edge to NULL module
149    printf("Check #N2:\n");
150    err = (*jvmti)->AddModuleReads(jvmti, baseModule, NULL);
151    if (err != JVMTI_ERROR_NULL_POINTER) {
152        printf("#N2: jvmtiError from AddModuleReads: %d\n", err);
153        throw_exc(env, "Check #N2: failed to return JVMTI_ERROR_NULL_POINTER for to_module==NULL");
154        return FAILED;
155    }
156
157    // Add an invalid read edge from invalid module (cls)
158    printf("Check #I1:\n");
159    err = (*jvmti)->AddModuleReads(jvmti, cls, baseModule);
160    if (err != JVMTI_ERROR_INVALID_MODULE) {
161        printf("#I1: jvmtiError from AddModuleReads: %d\n", err);
162        throw_exc(env, "Check #I1: failed to return JVMTI_ERROR_INVALID_MODULE for module==cls");
163        return FAILED;
164    }
165
166    // Add an invalid read edge to invalid module (cls)
167    printf("Check #I2:\n");
168    err = (*jvmti)->AddModuleReads(jvmti, baseModule, cls);
169    if (err != JVMTI_ERROR_INVALID_MODULE) {
170        printf("#I2: jvmtiError from AddModuleReads: %d\n", err);
171        throw_exc(env, "Check #I2: failed to return JVMTI_ERROR_INVALID_MODULE for to_module==cls");
172        return FAILED;
173    }
174
175    // Check the edge baseModule->instrModule is absent
176    printf("Check #C0:\n");
177    can = can_module_read(env, baseModule, instrModule);
178    if (can != JNI_FALSE) {
179        throw_exc(env, "Check #C0: read edge from base to instr is unexpected");
180        return FAILED;
181    }
182
183    // Add read edge baseModule->instrModule
184    printf("Check #C1:\n");
185    err = (*jvmti)->AddModuleReads(jvmti, baseModule, instrModule);
186    if (err != JVMTI_ERROR_NONE) {
187        printf("#C1: jvmtiError from AddModuleReads: %d\n", err);
188        throw_exc(env, "Check #C1: error in add reads from base to instr");
189        return FAILED;
190    }
191
192    // Check the read edge baseModule->instrModule is present now
193    printf("Check #C2:\n");
194    can = can_module_read(env, baseModule, instrModule);
195    if (can == JNI_FALSE) {
196        throw_exc(env, "Check #C2: failed to add reads from base to instr");
197        return FAILED;
198    }
199
200    // Check the read edge baseModule->unnamedModule is absent
201    printf("Check #C3:\n");
202    can = can_module_read(env, baseModule, unnamedModule);
203    if (can != JNI_FALSE) {
204        throw_exc(env, "Check #C3: got unexpected read edge from base to unnamed");
205        return FAILED;
206    }
207
208    // Add read edge baseModule->unnamedModule
209    printf("Check #C4:\n");
210    err = (*jvmti)->AddModuleReads(jvmti, baseModule, unnamedModule);
211    if (err != JVMTI_ERROR_NONE) {
212        printf("#C4: jvmtiError from AddModuleReads: %d\n", err);
213        throw_exc(env, "Check #C4: failed to ignore adding read edge from base to unnamed");
214        return FAILED;
215    }
216
217    // Check the read edge baseModule->unnamedModule is present now
218    printf("Check #C5:\n");
219    can = can_module_read(env, baseModule, unnamedModule);
220    if (can == JNI_FALSE) {
221        throw_exc(env, "Check #C5: did not get expected read edge from base to unnamed");
222        return FAILED;
223    }
224
225    // Check the read edge unnamedModule->instrModule is absent
226    printf("Check #C6:\n");
227    can = can_module_read(env, unnamedModule, instrModule);
228    if (can == JNI_FALSE) {
229        throw_exc(env, "Check #C6: did not get expected read edge from unnamed to instr");
230        return FAILED;
231    }
232
233    // Add read edge unnamedModule->instrModule
234    printf("Check #C7:\n");
235    err = (*jvmti)->AddModuleReads(jvmti, unnamedModule, instrModule);
236    if (err != JVMTI_ERROR_NONE) {
237        printf("#C7: jvmtiError from AddModuleReads: %d\n", err);
238        throw_exc(env, "Check #C7: failed to ignore adding read edge from unnamed to instr");
239        return FAILED;
240    }
241    return PASSED;
242}
243
244JNIEXPORT jint JNICALL
245Java_MyPackage_AddModuleReadsTest_check(JNIEnv *env,
246                                        jclass cls,
247                                        jobject unnamedModule,
248                                        jobject baseModule,
249                                        jobject instrModule) {
250    if (jvmti == NULL) {
251        throw_exc(env, "JVMTI client was not properly loaded!\n");
252        return FAILED;
253    }
254
255    printf("\n*** Checks for JVMTI AddModuleReads ***\n\n");
256    result = check_add_module_reads(env, cls, unnamedModule, baseModule, instrModule);
257    if (result != PASSED) {
258        return result;
259    }
260    return result;
261}
262
263#ifdef __cplusplus
264}
265#endif
266