1 /*
2  * Copyright (c) 2007, 2018, 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 <stdlib.h>
25 #include <string.h>
26 #include "jvmti.h"
27 #include "jni_tools.h"
28 #include "jvmti_tools.h"
29 #include "agent_common.h"
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 /* ============================================================================= */
36 
37 static jlong timeout = 0;
38 
39 static char segment1[3000] = "";
40 static char segment2[3000] = "";
41 
42 static const char* const illegal_segments[] = {"", "tmp/"};
43 
44 jboolean use_segment2 = JNI_FALSE;
45 
46 jvmtiPhase jvmti_phase_to_check = JVMTI_PHASE_ONLOAD;
47 
48 /* ============================================================================= */
49 
50 /**
51  * Add segment to bootstrap classloader path.
52  * @returns NSK_FALSE if any error occured.
53  */
addSegment(jvmtiEnv * jvmti,const char segment[],const char where[])54 static int addSegment(jvmtiEnv* jvmti, const char segment[], const char where[]) {
55     NSK_DISPLAY1("Add segment: \"%s\"\n", segment);
56     if (!NSK_JVMTI_VERIFY(
57             NSK_CPP_STUB2(AddToSystemClassLoaderSearch, jvmti, segment))) {
58         NSK_COMPLAIN1("TEST FAILURE: failed to add segment %s\n", segment);
59         return NSK_FALSE;
60     }
61     NSK_DISPLAY0("  ... added\n");
62 
63     return NSK_TRUE;
64 }
65 
66 /**
67  * Try to add illegal segment to bootstrap classloader path and check that expected error
68  *  (expectedError) is returned.
69  * @returns NSK_FALSE if no error or wronf error is occured.
70  */
addIllegalSegment(jvmtiEnv * jvmti,const char segment[],const char where[],jvmtiError expectedError)71 static int addIllegalSegment(jvmtiEnv* jvmti, const char segment[], const char where[], jvmtiError expectedError) {
72     NSK_DISPLAY1("Add illegal segment: \"%s\"\n", segment);
73     if (!NSK_JVMTI_VERIFY_CODE(expectedError,
74             NSK_CPP_STUB2(AddToSystemClassLoaderSearch, jvmti, segment))) {
75 
76         NSK_COMPLAIN2("TEST FAILURE: got wrong error when tried to add segment %s (expected error=%s)\n",
77                       segment, TranslateError(expectedError));
78         return NSK_FALSE;
79     }
80     NSK_DISPLAY0("  ... not added\n");
81 
82     return NSK_TRUE;
83 }
84 
85 /*
86  * Check that attempt to add illegal segment causes the error.
87  */
checkLivePhaseForIllegalArgs(jvmtiEnv * jvmti,const char where[])88 static void checkLivePhaseForIllegalArgs(jvmtiEnv* jvmti, const char where[]) {
89     size_t i;
90 
91     for (i = 0; i < sizeof(illegal_segments)/sizeof(char*); i++) {
92         if (!addIllegalSegment(jvmti, illegal_segments[i], where, JVMTI_ERROR_ILLEGAL_ARGUMENT)) {
93             nsk_jvmti_setFailStatus();
94             NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus()));
95         }
96     }
97 }
98 
99 /* ============================================================================= */
100 
101 void JNICALL
callbackVMInit(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)102 callbackVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) {
103     NSK_DISPLAY0(">>> Testcase #1: Add bootstrap class load segment(s) in VMInit (live phase)\n");
104 
105     // At first check that it is not possible to add anything other than an existing JAR file
106     checkLivePhaseForIllegalArgs(jvmti, "VMInit()");
107 
108     if (!addSegment(jvmti, segment1, "VMInit()")) {
109         nsk_jvmti_setFailStatus();
110         NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus()));
111     }
112 
113     if (use_segment2 == JNI_FALSE) return;
114 
115     if (!addSegment(jvmti, segment2, "VMInit()")) {
116         nsk_jvmti_setFailStatus();
117         NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus()));
118     }
119 }
120 
121 /*
122  * Check that it is possible to add to the boot class path before VMDeath event return.
123  */
124 void JNICALL
callbackVMDeath(jvmtiEnv * jvmti,JNIEnv * jni)125 callbackVMDeath(jvmtiEnv *jvmti, JNIEnv* jni) {
126     jvmtiPhase phase;
127 
128     if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB2(GetPhase, jvmti, &phase))) {
129         NSK_COMPLAIN0("TEST FAILURE: unable to get phase\n");
130         nsk_jvmti_setFailStatus();
131         NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus()));
132     }
133 
134     if (!NSK_VERIFY(phase == JVMTI_PHASE_LIVE)) {
135         NSK_DISPLAY0(">>> Testcase #1: Add bootstrap class load segment(s) in VMDeath (live phase)\n");
136 
137         // At first check that it is not possible to add anything other than an existing JAR file
138         checkLivePhaseForIllegalArgs(jvmti, "VMDeath()");
139 
140         /* Check, that it is possible to add a JAR file containing a class that is already
141         *  loaded (or is in the process of being loaded) by a _bootstrap_ class loader.
142         */
143 
144         if (!addSegment(jvmti, segment1, "VMDeath()")) {
145             nsk_jvmti_setFailStatus();
146             NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus()));
147         }
148 
149         if (use_segment2 == JNI_FALSE) return;
150         // otherwise add to classpath
151         if (!addSegment(jvmti, segment2, "VMDeath()")) {
152             nsk_jvmti_setFailStatus();
153             NSK_BEFORE_TRACE(exit(nsk_jvmti_getStatus()));
154         }
155     }
156 }
157 
158 /** Agent library initialization. */
Agent_Initialize(JavaVM * jvm,char * options,void * reserved)159 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
160     jvmtiEnv* jvmti;
161     const char *p_segment1, *p_segment2, *phase_to_check;
162 
163     jvmti = NULL;
164     p_segment1 = p_segment2 = phase_to_check = NULL;
165 
166     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
167         return JNI_ERR;
168 
169     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
170 
171     p_segment1 = nsk_jvmti_findOptionStringValue("segment1", NULL);
172     if (!NSK_VERIFY(p_segment1 != NULL)) {
173         return JNI_ERR;
174     } else {
175         strncpy(segment1, p_segment1, (size_t) sizeof(segment1)/sizeof(char));
176         segment1[(size_t) sizeof(segment1)/sizeof(char) - 1] = 0;
177     }
178 
179     // 'segment2' parameter is not mandatory
180     p_segment2 = nsk_jvmti_findOptionStringValue("segment2", NULL);
181     if (p_segment2 != NULL) {
182         strncpy(segment2, p_segment2, (size_t) sizeof(segment2)/sizeof(char));
183         segment2[(size_t) sizeof(segment2)/sizeof(char) - 1] = 0;
184         use_segment2 = JNI_TRUE;
185     }
186 
187     if (!NSK_VERIFY((jvmti =
188             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
189         return JNI_ERR;
190 
191     // Check what phase(s) we are going to test
192     phase_to_check = nsk_jvmti_findOptionStringValue("phasetocheck", NULL);
193     if (!NSK_VERIFY(phase_to_check != NULL)) {
194         return JNI_ERR;
195     } else if (strcmp(phase_to_check, "onload") == 0) {
196         jvmti_phase_to_check = JVMTI_PHASE_ONLOAD;
197     } else if (strcmp(phase_to_check, "live") == 0) {
198         jvmti_phase_to_check = JVMTI_PHASE_LIVE;
199     }
200 
201     if (jvmti_phase_to_check == JVMTI_PHASE_ONLOAD) {
202         NSK_DISPLAY0(">>> Testcase #1: Add bootstrap class load segment in Agent_OnLoad()\n");
203         if (!addSegment(jvmti, segment1, "Agent_OnLoad()")) {
204             return JNI_ERR;
205         }
206 
207         if (!addSegment(jvmti, segment2, "Agent_OnLoad()")) {
208             return JNI_ERR;
209         }
210 
211         return JNI_OK;
212     }
213 
214     /* For Live phase enable events and set callbacks for them */
215     NSK_DISPLAY1("Set callback for events: %s\n", "VM_INIT, VM_DEATH");
216     {
217         jvmtiEventCallbacks eventCallbacks;
218         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
219 
220         eventCallbacks.VMInit = callbackVMInit;
221         eventCallbacks.VMDeath = callbackVMDeath;
222 
223         if (!NSK_JVMTI_VERIFY(NSK_CPP_STUB3(SetEventCallbacks, jvmti,
224                                             &eventCallbacks, sizeof(eventCallbacks)))) {
225             return JNI_ERR;
226         }
227     }
228     NSK_DISPLAY0("  ... set\n");
229 
230     NSK_DISPLAY1("Enable events: %s\n", "VM_INIT, VM_DEATH");
231     {
232 
233         jvmtiEvent eventsList[] = { JVMTI_EVENT_VM_INIT, JVMTI_EVENT_VM_DEATH };
234         if (!NSK_VERIFY(nsk_jvmti_enableEvents(
235                      JVMTI_ENABLE, sizeof(eventsList)/sizeof(jvmtiEvent), eventsList, NULL))) {
236             return JNI_ERR;
237         }
238     }
239     NSK_DISPLAY0("  ... enabled\n");
240 
241     return JNI_OK;
242 }
243 
244 /* ============================================================================= */
245 
246 #ifdef __cplusplus
247 }
248 #endif
249