Bug Summary

File:jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c
Warning:line 605, column 26
Access to field 'mAgent' results in a dereference of a null pointer (loaded from variable 'environment')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name InvocationAdapter.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -D LIBC=gnu -D _GNU_SOURCE -D _REENTRANT -D _LARGEFILE64_SOURCE -D LINUX -D DEBUG -D _LITTLE_ENDIAN -D ARCH="amd64" -D amd64 -D _LP64=1 -I /home/daniel/Projects/java/jdk/src/java.instrument/unix/native/libinstrument -I /home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/java.instrument -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjli -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjli -D JPLIS_LOGGING -D _FORTIFY_SOURCE=2 -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wno-unused -Wno-unused-function -std=c99 -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c /home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c
1/*
2 * Copyright (c) 2003, 2021, 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/*
27 * Copyright 2003 Wily Technology, Inc.
28 */
29
30#include <string.h>
31#include <stdlib.h>
32
33#include "jni.h"
34
35#include "jdk_util.h"
36
37#include "Utilities.h"
38#include "JPLISAssert.h"
39#include "JPLISAgent.h"
40#include "JavaExceptions.h"
41
42#include "EncodingSupport.h"
43#include "FileSystemSupport.h"
44#include "JarFacade.h"
45#include "PathCharsValidator.h"
46
47/**
48 * This module contains the direct interface points with the JVMTI.
49 * The OnLoad handler is here, along with the various event handlers.
50 */
51
52static int
53appendClassPath(JPLISAgent* agent,
54 const char* jarfile);
55
56static void
57appendBootClassPath(JPLISAgent* agent,
58 const char* jarfile,
59 const char* pathList);
60
61
62/*
63 * Parse -javaagent tail, of the form name[=options], into name
64 * and options. Returned values are heap allocated and options maybe
65 * NULL. Returns 0 if parse succeeds, -1 if allocation fails.
66 */
67static int
68parseArgumentTail(char* tail, char** name, char** options) {
69 int len;
70 char* pos;
71
72 pos = strchr(tail, '=');
73 len = (pos == NULL((void*)0)) ? (int)strlen(tail) : (int)(pos - tail);
74
75 *name = (char*)malloc(len+1);
76 if (*name == NULL((void*)0)) {
77 return -1;
78 }
79 memcpy(*name, tail, len);
80 (*name)[len] = '\0';
81
82 if (pos == NULL((void*)0)) {
83 *options = NULL((void*)0);
84 } else {
85 char * str = (char*)malloc( (int)strlen(pos + 1) + 1 );
86 if (str == NULL((void*)0)) {
87 free(*name);
88 return -1;
89 }
90 strcpy(str, pos +1);
91 *options = str;
92 }
93 return 0;
94}
95
96/*
97 * Get the value of an attribute in an attribute list. Returns NULL
98 * if attribute not found.
99 */
100jboolean
101getBooleanAttribute(const jarAttribute* attributes, const char* name) {
102 char* attributeValue = getAttribute(attributes, name);
103 return attributeValue != NULL((void*)0) && strcasecmp(attributeValue, "true") == 0;
104}
105
106/*
107 * Parse any capability settings in the JAR manifest and
108 * convert them to JVM TI capabilities.
109 */
110void
111convertCapabilityAttributes(const jarAttribute* attributes, JPLISAgent* agent) {
112 /* set redefineClasses capability */
113 if (getBooleanAttribute(attributes, "Can-Redefine-Classes")) {
114 addRedefineClassesCapability(agent);
115 }
116
117 /* create an environment which has the retransformClasses capability */
118 if (getBooleanAttribute(attributes, "Can-Retransform-Classes")) {
119 retransformableEnvironment(agent);
120 }
121
122 /* set setNativeMethodPrefix capability */
123 if (getBooleanAttribute(attributes, "Can-Set-Native-Method-Prefix")) {
124 addNativeMethodPrefixCapability(agent);
125 }
126
127 /* for retransformClasses testing, set capability to use original method order */
128 if (getBooleanAttribute(attributes, "Can-Maintain-Original-Method-Order")) {
129 addOriginalMethodOrderCapability(agent);
130 }
131}
132
133/*
134 * This will be called once for every -javaagent on the command line.
135 * Each call to Agent_OnLoad will create its own agent and agent data.
136 *
137 * The argument tail string provided to Agent_OnLoad will be of form
138 * <jarfile>[=<options>]. The tail string is split into the jarfile and
139 * options components. The jarfile manifest is parsed and the value of the
140 * Premain-Class attribute will become the agent's premain class. The jar
141 * file is then added to the system class path, and if the Boot-Class-Path
142 * attribute is present then all relative URLs in the value are processed
143 * to create boot class path segments to append to the boot class path.
144 */
145JNIEXPORT__attribute__((visibility("default"))) jint JNICALL
146DEF_Agent_OnLoadAgent_OnLoad(JavaVM *vm, char *tail, void * reserved) {
147 JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;
148 jint result = JNI_OK0;
149 JPLISAgent * agent = NULL((void*)0);
150
151 initerror = createNewJPLISAgent(vm, &agent);
152 if ( initerror == JPLIS_INIT_ERROR_NONE ) {
153 int oldLen, newLen;
154 char * jarfile;
155 char * options;
156 jarAttribute* attributes;
157 char * premainClass;
158 char * bootClassPath;
159
160 /*
161 * Parse <jarfile>[=options] into jarfile and options
162 */
163 if (parseArgumentTail(tail, &jarfile, &options) != 0) {
164 fprintf(stderr, "-javaagent: memory allocation failure.\n")__fprintf_chk (stderr, 2 - 1, "-javaagent: memory allocation failure.\n"
)
;
165 return JNI_ERR(-1);
166 }
167
168 /*
169 * Agent_OnLoad is specified to provide the agent options
170 * argument tail in modified UTF8. However for 1.5.0 this is
171 * actually in the platform encoding - see 5049313.
172 *
173 * Open zip/jar file and parse archive. If can't be opened or
174 * not a zip file return error. Also if Premain-Class attribute
175 * isn't present we return an error.
176 */
177 attributes = readAttributes(jarfile);
178 if (attributes == NULL((void*)0)) {
179 fprintf(stderr, "Error opening zip file or JAR manifest missing : %s\n", jarfile)__fprintf_chk (stderr, 2 - 1, "Error opening zip file or JAR manifest missing : %s\n"
, jarfile)
;
180 free(jarfile);
181 if (options != NULL((void*)0)) free(options);
182 return JNI_ERR(-1);
183 }
184
185 premainClass = getAttribute(attributes, "Premain-Class");
186 if (premainClass == NULL((void*)0)) {
187 fprintf(stderr, "Failed to find Premain-Class manifest attribute in %s\n",__fprintf_chk (stderr, 2 - 1, "Failed to find Premain-Class manifest attribute in %s\n"
, jarfile)
188 jarfile)__fprintf_chk (stderr, 2 - 1, "Failed to find Premain-Class manifest attribute in %s\n"
, jarfile)
;
189 free(jarfile);
190 if (options != NULL((void*)0)) free(options);
191 freeAttributes(attributes);
192 return JNI_ERR(-1);
193 }
194
195 /* Save the jarfile name */
196 agent->mJarfile = jarfile;
197
198 /*
199 * The value of the Premain-Class attribute becomes the agent
200 * class name. The manifest is in UTF8 so need to convert to
201 * modified UTF8 (see JNI spec).
202 */
203 oldLen = (int)strlen(premainClass);
204 newLen = modifiedUtf8LengthOfUtf8(premainClass, oldLen);
205 /*
206 * According to JVMS class name is represented as CONSTANT_Utf8_info,
207 * so its length is u2 (i.e. must be <= 0xFFFF).
208 * Negative oldLen or newLen means we got signed integer overflow
209 * (modifiedUtf8LengthOfUtf8 returns negative value if oldLen is negative).
210 */
211 if (oldLen < 0 || newLen < 0 || newLen > 0xFFFF) {
212 fprintf(stderr, "-javaagent: Premain-Class value is too big\n")__fprintf_chk (stderr, 2 - 1, "-javaagent: Premain-Class value is too big\n"
)
;
213 free(jarfile);
214 if (options != NULL((void*)0)) free(options);
215 freeAttributes(attributes);
216 return JNI_ERR(-1);
217 }
218 if (newLen == oldLen) {
219 premainClass = strdup(premainClass);
220 } else {
221 char* str = (char*)malloc( newLen+1 );
222 if (str != NULL((void*)0)) {
223 convertUtf8ToModifiedUtf8(premainClass, oldLen, str, newLen);
224 }
225 premainClass = str;
226 }
227 if (premainClass == NULL((void*)0)) {
228 fprintf(stderr, "-javaagent: memory allocation failed\n")__fprintf_chk (stderr, 2 - 1, "-javaagent: memory allocation failed\n"
)
;
229 free(jarfile);
230 if (options != NULL((void*)0)) free(options);
231 freeAttributes(attributes);
232 return JNI_ERR(-1);
233 }
234
235 /*
236 * If the Boot-Class-Path attribute is specified then we process
237 * each relative URL and add it to the bootclasspath.
238 */
239 bootClassPath = getAttribute(attributes, "Boot-Class-Path");
240 if (bootClassPath != NULL((void*)0)) {
241 appendBootClassPath(agent, jarfile, bootClassPath);
242 }
243
244 /*
245 * Convert JAR attributes into agent capabilities
246 */
247 convertCapabilityAttributes(attributes, agent);
248
249 /*
250 * Track (record) the agent class name and options data
251 */
252 initerror = recordCommandLineData(agent, premainClass, options);
253
254 /*
255 * Clean-up
256 */
257 if (options != NULL((void*)0)) free(options);
258 freeAttributes(attributes);
259 free(premainClass);
260 }
261
262 switch (initerror) {
263 case JPLIS_INIT_ERROR_NONE:
264 result = JNI_OK0;
265 break;
266 case JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT:
267 result = JNI_ERR(-1);
268 fprintf(stderr, "java.lang.instrument/-javaagent: cannot create native agent.\n")__fprintf_chk (stderr, 2 - 1, "java.lang.instrument/-javaagent: cannot create native agent.\n"
)
;
269 break;
270 case JPLIS_INIT_ERROR_FAILURE:
271 result = JNI_ERR(-1);
272 fprintf(stderr, "java.lang.instrument/-javaagent: initialization of native agent failed.\n")__fprintf_chk (stderr, 2 - 1, "java.lang.instrument/-javaagent: initialization of native agent failed.\n"
)
;
273 break;
274 case JPLIS_INIT_ERROR_ALLOCATION_FAILURE:
275 result = JNI_ERR(-1);
276 fprintf(stderr, "java.lang.instrument/-javaagent: allocation failure.\n")__fprintf_chk (stderr, 2 - 1, "java.lang.instrument/-javaagent: allocation failure.\n"
)
;
277 break;
278 case JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED:
279 result = JNI_ERR(-1);
280 fprintf(stderr, "-javaagent: agent class not specified.\n")__fprintf_chk (stderr, 2 - 1, "-javaagent: agent class not specified.\n"
)
;
281 break;
282 default:
283 result = JNI_ERR(-1);
284 fprintf(stderr, "java.lang.instrument/-javaagent: unknown error\n")__fprintf_chk (stderr, 2 - 1, "java.lang.instrument/-javaagent: unknown error\n"
)
;
285 break;
286 }
287 return result;
288}
289
290/*
291 * Agent_OnAttach returns a jint. 0/JNI_OK indicates success and non-0
292 * indicates an error. To allow the attach mechanism throw an
293 * AgentInitializationException with a reasonable exception message we define
294 * a few specific errors here.
295 */
296#define AGENT_ERROR_BADJAR((jint)100) ((jint)100) /* Agent JAR not found or no Agent-Class attribute */
297#define AGENT_ERROR_NOTONCP((jint)101) ((jint)101) /* Unable to add JAR file to system class path */
298#define AGENT_ERROR_STARTFAIL((jint)102) ((jint)102) /* No agentmain method or agentmain failed */
299
300/*
301 * This will be called once each time a tool attaches to the VM and loads
302 * the JPLIS library.
303 */
304JNIEXPORT__attribute__((visibility("default"))) jint JNICALL
305DEF_Agent_OnAttachAgent_OnAttach(JavaVM* vm, char *args, void * reserved) {
306 JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;
307 jint result = JNI_OK0;
308 JPLISAgent * agent = NULL((void*)0);
309 JNIEnv * jni_env = NULL((void*)0);
310
311 /*
312 * Need JNIEnv - guaranteed to be called from thread that is already
313 * attached to VM
314 */
315 result = (*vm)->GetEnv(vm, (void**)&jni_env, JNI_VERSION_1_20x00010002);
316 jplis_assert(result==JNI_OK)JPLISAssertCondition((jboolean)(result==0), "result==JNI_OK",
"/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 316)
;
317
318 initerror = createNewJPLISAgent(vm, &agent);
319 if ( initerror == JPLIS_INIT_ERROR_NONE ) {
320 int oldLen, newLen;
321 char * jarfile;
322 char * options;
323 jarAttribute* attributes;
324 char * agentClass;
325 char * bootClassPath;
326 jboolean success;
327
328 /*
329 * Parse <jarfile>[=options] into jarfile and options
330 */
331 if (parseArgumentTail(args, &jarfile, &options) != 0) {
332 return JNI_ENOMEM(-4);
333 }
334
335 /*
336 * Open the JAR file and parse the manifest
337 */
338 attributes = readAttributes( jarfile );
339 if (attributes == NULL((void*)0)) {
340 fprintf(stderr, "Error opening zip file or JAR manifest missing: %s\n", jarfile)__fprintf_chk (stderr, 2 - 1, "Error opening zip file or JAR manifest missing: %s\n"
, jarfile)
;
341 free(jarfile);
342 if (options != NULL((void*)0)) free(options);
343 return AGENT_ERROR_BADJAR((jint)100);
344 }
345
346 agentClass = getAttribute(attributes, "Agent-Class");
347 if (agentClass == NULL((void*)0)) {
348 fprintf(stderr, "Failed to find Agent-Class manifest attribute from %s\n",__fprintf_chk (stderr, 2 - 1, "Failed to find Agent-Class manifest attribute from %s\n"
, jarfile)
349 jarfile)__fprintf_chk (stderr, 2 - 1, "Failed to find Agent-Class manifest attribute from %s\n"
, jarfile)
;
350 free(jarfile);
351 if (options != NULL((void*)0)) free(options);
352 freeAttributes(attributes);
353 return AGENT_ERROR_BADJAR((jint)100);
354 }
355
356 /*
357 * Add the jarfile to the system class path
358 */
359 if (appendClassPath(agent, jarfile)) {
360 fprintf(stderr, "Unable to add %s to system class path "__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path "
"- not supported by system class loader or configuration error!\n"
, jarfile)
361 "- not supported by system class loader or configuration error!\n",__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path "
"- not supported by system class loader or configuration error!\n"
, jarfile)
362 jarfile)__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path "
"- not supported by system class loader or configuration error!\n"
, jarfile)
;
363 free(jarfile);
364 if (options != NULL((void*)0)) free(options);
365 freeAttributes(attributes);
366 return AGENT_ERROR_NOTONCP((jint)101);
367 }
368
369 /*
370 * The value of the Agent-Class attribute becomes the agent
371 * class name. The manifest is in UTF8 so need to convert to
372 * modified UTF8 (see JNI spec).
373 */
374 oldLen = (int)strlen(agentClass);
375 newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen);
376 /*
377 * According to JVMS class name is represented as CONSTANT_Utf8_info,
378 * so its length is u2 (i.e. must be <= 0xFFFF).
379 * Negative oldLen or newLen means we got signed integer overflow
380 * (modifiedUtf8LengthOfUtf8 returns negative value if oldLen is negative).
381 */
382 if (oldLen < 0 || newLen < 0 || newLen > 0xFFFF) {
383 fprintf(stderr, "Agent-Class value is too big\n")__fprintf_chk (stderr, 2 - 1, "Agent-Class value is too big\n"
)
;
384 free(jarfile);
385 if (options != NULL((void*)0)) free(options);
386 freeAttributes(attributes);
387 return AGENT_ERROR_BADJAR((jint)100);
388 }
389 if (newLen == oldLen) {
390 agentClass = strdup(agentClass);
391 } else {
392 char* str = (char*)malloc( newLen+1 );
393 if (str != NULL((void*)0)) {
394 convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen);
395 }
396 agentClass = str;
397 }
398 if (agentClass == NULL((void*)0)) {
399 free(jarfile);
400 if (options != NULL((void*)0)) free(options);
401 freeAttributes(attributes);
402 return JNI_ENOMEM(-4);
403 }
404
405 /*
406 * If the Boot-Class-Path attribute is specified then we process
407 * each URL - in the live phase only JAR files will be added.
408 */
409 bootClassPath = getAttribute(attributes, "Boot-Class-Path");
410 if (bootClassPath != NULL((void*)0)) {
411 appendBootClassPath(agent, jarfile, bootClassPath);
412 }
413
414 /*
415 * Convert JAR attributes into agent capabilities
416 */
417 convertCapabilityAttributes(attributes, agent);
418
419 /*
420 * Create the java.lang.instrument.Instrumentation instance
421 */
422 success = createInstrumentationImpl(jni_env, agent);
423 jplis_assert(success)JPLISAssertCondition((jboolean)(success), "success", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 423)
;
424
425 /*
426 * Setup ClassFileLoadHook handler.
427 */
428 if (success) {
429 success = setLivePhaseEventHandlers(agent);
430 jplis_assert(success)JPLISAssertCondition((jboolean)(success), "success", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 430)
;
431 }
432
433 /*
434 * Start the agent
435 */
436 if (success) {
437 success = startJavaAgent(agent,
438 jni_env,
439 agentClass,
440 options,
441 agent->mAgentmainCaller);
442 }
443
444 if (!success) {
445 fprintf(stderr, "Agent failed to start!\n")__fprintf_chk (stderr, 2 - 1, "Agent failed to start!\n");
446 result = AGENT_ERROR_STARTFAIL((jint)102);
447 }
448
449 /*
450 * Clean-up
451 */
452 free(jarfile);
453 if (options != NULL((void*)0)) free(options);
454 free(agentClass);
455 freeAttributes(attributes);
456 }
457
458 return result;
459}
460
461
462JNIEXPORT__attribute__((visibility("default"))) void JNICALL
463DEF_Agent_OnUnloadAgent_OnUnload(JavaVM *vm) {
464}
465
466/**
467 * Invoked by the java launcher to load an agent in the main executable JAR.
468 * The Launcher-Agent-Class attribute in the main manifest of the JAR file
469 * is the agent class.
470 *
471 * Returns JNI_OK if the agent is loaded and initialized; JNI_ERR if this
472 * function fails, possibly with a pending exception.
473 */
474jint loadAgent(JNIEnv* env, jstring path) {
475 JavaVM* vm;
476 JPLISAgent* agent;
477 const char* jarfile = NULL((void*)0);
478 jarAttribute* attributes = NULL((void*)0);
479 char* agentClass = NULL((void*)0);
480 char* bootClassPath;
481 int oldLen, newLen;
482 jint result = JNI_ERR(-1);
483
484 if ((*env)->GetJavaVM(env, &vm) < 0) {
485 return JNI_ERR(-1);
486 }
487
488 // create JPLISAgent with JVMTI environment
489 if (createNewJPLISAgent(vm, &agent) != JPLIS_INIT_ERROR_NONE) {
490 return JNI_ERR(-1);
491 }
492
493 // get path to JAR file as UTF-8 string
494 jarfile = (*env)->GetStringUTFChars(env, path, NULL((void*)0));
495 if (jarfile == NULL((void*)0)) {
496 return JNI_ERR(-1);
497 }
498
499 // read the attributes in the main section of JAR manifest
500 attributes = readAttributes(jarfile);
501 if (attributes == NULL((void*)0)) {
502 goto releaseAndReturn;
503 }
504
505 // Launcher-Agent-Class is required
506 agentClass = getAttribute(attributes, "Launcher-Agent-Class");
507 if (agentClass == NULL((void*)0)) {
508 goto releaseAndReturn;
509 }
510
511 // The value of Launcher-Agent-Class is in UTF-8, convert it to modified UTF-8
512 oldLen = (int) strlen(agentClass);
513 newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen);
514 /*
515 * According to JVMS class name is represented as CONSTANT_Utf8_info,
516 * so its length is u2 (i.e. must be <= 0xFFFF).
517 * Negative oldLen or newLen means we got signed integer overflow
518 * (modifiedUtf8LengthOfUtf8 returns negative value if oldLen is negative).
519 */
520 if (oldLen < 0 || newLen < 0 || newLen > 0xFFFF) {
521 goto releaseAndReturn;
522 }
523 if (newLen == oldLen) {
524 agentClass = strdup(agentClass);
525 } else {
526 char* str = (char*) malloc(newLen + 1);
527 if (str != NULL((void*)0)) {
528 convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen);
529 }
530 agentClass = str;
531 }
532 if (agentClass == NULL((void*)0)) {
533 jthrowable oome = createThrowable(env, "java/lang/OutOfMemoryError", NULL((void*)0));
534 if (oome != NULL((void*)0)) (*env)->Throw(env, oome);
535 goto releaseAndReturn;
536 }
537
538 // Boot-Class-Path
539 bootClassPath = getAttribute(attributes, "Boot-Class-Path");
540 if (bootClassPath != NULL((void*)0)) {
541 appendBootClassPath(agent, jarfile, bootClassPath);
542 }
543
544 // Can-XXXX capabilities
545 convertCapabilityAttributes(attributes, agent);
546
547 // Create the java.lang.instrument.Instrumentation object
548 if (!createInstrumentationImpl(env, agent)) {
549 goto releaseAndReturn;
550 }
551
552 // Enable the ClassFileLoadHook
553 if (!setLivePhaseEventHandlers(agent)) {
554 goto releaseAndReturn;
555 }
556
557 // invoke the agentmain method
558 if (!startJavaAgent(agent, env, agentClass, "", agent->mAgentmainCaller)) {
559 goto releaseAndReturn;
560 }
561
562 // initialization complete
563 result = JNI_OK0;
564
565releaseAndReturn:
566 if (agentClass != NULL((void*)0)) {
567 free(agentClass);
568 }
569 if (attributes != NULL((void*)0)) {
570 freeAttributes(attributes);
571 }
572 if (jarfile != NULL((void*)0)) {
573 (*env)->ReleaseStringUTFChars(env, path, jarfile);
574 }
575
576 return result;
577}
578
579/*
580 * JVMTI callback support
581 *
582 * We have two "stages" of callback support.
583 * At OnLoad time, we install a VMInit handler.
584 * When the VMInit handler runs, we remove the VMInit handler and install a
585 * ClassFileLoadHook handler.
586 */
587
588void JNICALL
589eventHandlerVMInit( jvmtiEnv * jvmtienv,
590 JNIEnv * jnienv,
591 jthread thread) {
592 JPLISEnvironment * environment = NULL((void*)0);
593 jboolean success = JNI_FALSE0;
594
595 environment = getJPLISEnvironment(jvmtienv);
1
Value assigned to 'environment'
596
597 /* process the premain calls on the all the JPL agents */
598 if (environment == NULL((void*)0)) {
2
Assuming 'environment' is equal to NULL
3
Taking true branch
599 abortJVM(jnienv, JPLIS_ERRORMESSAGE_CANNOTSTART"processing of -javaagent failed" ", getting JPLIS environment failed");
600 }
601 jthrowable outstandingException = NULL((void*)0);
602 /*
603 * Add the jarfile to the system class path
604 */
605 JPLISAgent * agent = environment->mAgent;
4
Access to field 'mAgent' results in a dereference of a null pointer (loaded from variable 'environment')
606 if (appendClassPath(agent, agent->mJarfile)) {
607 fprintf(stderr, "Unable to add %s to system class path - "__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path - "
"the system class loader does not define the " "appendToClassPathForInstrumentation method or the method failed\n"
, agent->mJarfile)
608 "the system class loader does not define the "__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path - "
"the system class loader does not define the " "appendToClassPathForInstrumentation method or the method failed\n"
, agent->mJarfile)
609 "appendToClassPathForInstrumentation method or the method failed\n",__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path - "
"the system class loader does not define the " "appendToClassPathForInstrumentation method or the method failed\n"
, agent->mJarfile)
610 agent->mJarfile)__fprintf_chk (stderr, 2 - 1, "Unable to add %s to system class path - "
"the system class loader does not define the " "appendToClassPathForInstrumentation method or the method failed\n"
, agent->mJarfile)
;
611 free((void *)agent->mJarfile);
612 abortJVM(jnienv, JPLIS_ERRORMESSAGE_CANNOTSTART"processing of -javaagent failed" ", appending to system class path failed");
613 }
614 free((void *)agent->mJarfile);
615 agent->mJarfile = NULL((void*)0);
616
617 outstandingException = preserveThrowable(jnienv);
618 success = processJavaStart( environment->mAgent, jnienv);
619 restoreThrowable(jnienv, outstandingException);
620
621 /* if we fail to start cleanly, bring down the JVM */
622 if ( !success ) {
623 abortJVM(jnienv, JPLIS_ERRORMESSAGE_CANNOTSTART"processing of -javaagent failed" ", processJavaStart failed");
624 }
625}
626
627void JNICALL
628eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv,
629 JNIEnv * jnienv,
630 jclass class_being_redefined,
631 jobject loader,
632 const char* name,
633 jobject protectionDomain,
634 jint class_data_len,
635 const unsigned char* class_data,
636 jint* new_class_data_len,
637 unsigned char** new_class_data) {
638 JPLISEnvironment * environment = NULL((void*)0);
639
640 environment = getJPLISEnvironment(jvmtienv);
641
642 /* if something is internally inconsistent (no agent), just silently return without touching the buffer */
643 if ( environment != NULL((void*)0) ) {
644 jthrowable outstandingException = preserveThrowable(jnienv);
645 transformClassFile( environment->mAgent,
646 jnienv,
647 loader,
648 name,
649 class_being_redefined,
650 protectionDomain,
651 class_data_len,
652 class_data,
653 new_class_data_len,
654 new_class_data,
655 environment->mIsRetransformer);
656 restoreThrowable(jnienv, outstandingException);
657 }
658}
659
660
661
662
663/*
664 * URLs in Boot-Class-Path attributes are separated by one or more spaces.
665 * This function splits the attribute value into a list of path segments.
666 * The attribute value is in UTF8 but cannot contain NUL. Also non US-ASCII
667 * characters must be escaped (URI syntax) so safe to iterate through the
668 * value as a C string.
669 */
670static void
671splitPathList(const char* str, int* pathCount, char*** paths) {
672 int count = 0;
673 char** segments = NULL((void*)0);
674 char** new_segments;
675 char* c = (char*) str;
676 while (*c != '\0') {
677 while (*c == ' ') c++; /* skip leading spaces */
678 if (*c == '\0') {
679 break;
680 }
681 new_segments = (char**)realloc(segments, (count+1)*sizeof(char*));
682 if (new_segments == NULL((void*)0)) {
683 jplis_assert(0)JPLISAssertCondition((jboolean)(0), "0", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 683)
;
684 free(segments);
685 count = 0;
686 segments = NULL((void*)0);
687 break;
688 }
689 segments = new_segments;
690 segments[count++] = c;
691 c = strchr(c, ' ');
692 if (c == NULL((void*)0)) {
693 break;
694 }
695 *c = '\0';
696 c++;
697 }
698 *pathCount = count;
699 *paths = segments;
700}
701
702
703/* URI path decoding - ported from src/share/classes/java/net/URI.java */
704
705static int
706decodeNibble(char c) {
707 if ((c >= '0') && (c <= '9'))
708 return c - '0';
709 if ((c >= 'a') && (c <= 'f'))
710 return c - 'a' + 10;
711 if ((c >= 'A') && (c <= 'F'))
712 return c - 'A' + 10;
713 return -1;
714}
715
716static int
717decodeByte(char c1, char c2) {
718 return (((decodeNibble(c1) & 0xf) << 4) | ((decodeNibble(c2) & 0xf) << 0));
719}
720
721/*
722 * Evaluates all escapes in s. Assumes that escapes are well-formed
723 * syntactically, i.e., of the form %XX.
724 * If the path does not require decoding the original path is
725 * returned. Otherwise the decoded path (heap allocated) is returned,
726 * along with the length of the decoded path. Note that the return
727 * string will not be null terminated after decoding.
728 */
729static
730char *decodePath(const char *s, int* decodedLen) {
731 int n;
732 char *result;
733 char *resultp;
734 int c;
735 int i;
736
737 n = (int)strlen(s);
738 if (n == 0) {
739 *decodedLen = 0;
740 return (char*)s;
741 }
742 if (strchr(s, '%') == NULL((void*)0)) {
743 *decodedLen = n;
744 return (char*)s; /* no escapes, we are done */
745 }
746
747 resultp = result = calloc(n+1, 1);
748 if (result == NULL((void*)0)) {
749 *decodedLen = 0;
750 return NULL((void*)0);
751 }
752 c = s[0];
753 for (i = 0; i < n;) {
754 if (c != '%') {
755 *resultp++ = c;
756 if (++i >= n)
757 break;
758 c = s[i];
759 continue;
760 }
761 for (;;) {
762 char b1 = s[++i];
763 char b2 = s[++i];
764 int decoded = decodeByte(b1, b2);
765 *resultp++ = decoded;
766 if (++i >= n)
767 break;
768 c = s[i];
769 if (c != '%')
770 break;
771 }
772 }
773 *decodedLen = (int)(resultp - result);
774 return result; // not null terminated.
775}
776
777/*
778 * Append the given jar file to the system class path. This should succeed in the
779 * onload phase but may fail in the live phase if the system class loader doesn't
780 * support appending to the class path.
781 */
782static int
783appendClassPath( JPLISAgent* agent,
784 const char* jarfile ) {
785 jvmtiEnv* jvmtienv = jvmti(agent)agent->mNormalEnvironment.mJVMTIEnv;
786 jvmtiError jvmtierr;
787
788 jvmtierr = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, jarfile);
789 check_phase_ret_1(jvmtierr)if ((jvmtierr) == JVMTI_ERROR_WRONG_PHASE) { return 1; };
790
791 switch (jvmtierr) {
792 case JVMTI_ERROR_NONE :
793 return 0;
794 case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED :
795 fprintf(stderr, "System class loader does not define "__fprintf_chk (stderr, 2 - 1, "System class loader does not define "
"the appendToClassPathForInstrumentation method\n")
796 "the appendToClassPathForInstrumentation method\n")__fprintf_chk (stderr, 2 - 1, "System class loader does not define "
"the appendToClassPathForInstrumentation method\n")
;
797 break;
798 default:
799 fprintf(stderr, "Unexpected error (%d) returned by "__fprintf_chk (stderr, 2 - 1, "Unexpected error (%d) returned by "
"AddToSystemClassLoaderSearch\n", jvmtierr)
800 "AddToSystemClassLoaderSearch\n", jvmtierr)__fprintf_chk (stderr, 2 - 1, "Unexpected error (%d) returned by "
"AddToSystemClassLoaderSearch\n", jvmtierr)
;
801 break;
802 }
803 return -1;
804}
805
806
807/*
808 * res = func, free'ing the previous value of 'res' if function
809 * returns a new result.
810 */
811#define TRANSFORM(res,func){ char* tmp = func; if (tmp != res) { free(res); res = tmp; }
JPLISAssertCondition((jboolean)((void*)res != (void*)((void*
)0)), "(void*)res != (void*)NULL", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 811); }
{ \
812 char* tmp = func; \
813 if (tmp != res) { \
814 free(res); \
815 res = tmp; \
816 } \
817 jplis_assert((void*)res != (void*)NULL)JPLISAssertCondition((jboolean)((void*)res != (void*)((void*)
0)), "(void*)res != (void*)NULL", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 817)
; \
818}
819
820/*
821 * This function takes the value of the Boot-Class-Path attribute,
822 * splits it into the individual path segments, and then combines it
823 * with the path to the jar file to create the path to be added
824 * to the bootclasspath.
825 *
826 * Each individual path segment starts out as a UTF8 string. Additionally
827 * as the path is specified to use URI path syntax all non US-ASCII
828 * characters are escaped. Once the URI path is decoded we get a UTF8
829 * string which must then be converted to the platform encoding (as it
830 * will be combined with the platform path of the jar file). Once
831 * converted it is then normalized (remove duplicate slashes, etc.).
832 * If the resulting path is an absolute path (starts with a slash for
833 * example) then the path will be added to the bootclasspath. Otherwise
834 * if it's not absolute then we get the canonical path of the agent jar
835 * file and then resolve the path in the context of the base path of
836 * the agent jar.
837 */
838static void
839appendBootClassPath( JPLISAgent* agent,
840 const char* jarfile,
841 const char* pathList ) {
842 char canonicalPath[MAXPATHLEN4096];
843 char *parent = NULL((void*)0);
844 int haveBasePath = 0;
845
846 int count, i;
847 char **paths;
848 jvmtiEnv* jvmtienv = jvmti(agent)agent->mNormalEnvironment.mJVMTIEnv;
849 jvmtiError jvmtierr;
850
851 /*
852 * Split the attribute value into the individual path segments
853 * and process each in sequence
854 */
855 splitPathList(pathList, &count, &paths);
856
857 for (i=0; i<count; i++) {
858 int len;
859 char* path;
860 char* pos;
861
862 /*
863 * The path segment at this point is a pointer into the attribute
864 * value. As it will go through a number of transformation (tossing away
865 * the previous results as we go along) it make it easier if the path
866 * starts out as a heap allocated string.
867 */
868 path = strdup(paths[i]);
869 jplis_assert(path != (char*)NULL)JPLISAssertCondition((jboolean)(path != (char*)((void*)0)), "path != (char*)NULL"
, "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 869)
;
870
871 /*
872 * The attribute is specified to be a list of relative URIs so in theory
873 * there could be a query component - if so, get rid of it.
874 */
875 pos = strchr(path, '?');
876 if (pos != NULL((void*)0)) {
877 *pos = '\0';
878 }
879
880 /*
881 * Check for characters that are not allowed in the path component of
882 * a URI.
883 */
884 if (validatePathChars(path)) {
885 fprintf(stderr, "WARNING: illegal character in Boot-Class-Path value: %s\n",__fprintf_chk (stderr, 2 - 1, "WARNING: illegal character in Boot-Class-Path value: %s\n"
, path)
886 path)__fprintf_chk (stderr, 2 - 1, "WARNING: illegal character in Boot-Class-Path value: %s\n"
, path)
;
887 free(path);
888 continue;
889 }
890
891
892 /*
893 * Next decode any escaped characters. The result is a UTF8 string.
894 */
895 TRANSFORM(path, decodePath(path,&len)){ char* tmp = decodePath(path,&len); if (tmp != path) { free
(path); path = tmp; } JPLISAssertCondition((jboolean)((void*)
path != (void*)((void*)0)), "(void*)path != (void*)NULL", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 895); }
;
896
897 /*
898 * Convert to the platform encoding
899 */
900 {
901 char platform[MAXPATHLEN4096];
902 int new_len = convertUtf8ToPlatformString(path, len, platform, MAXPATHLEN4096);
903 free(path);
904 if (new_len < 0) {
905 /* bogus value - exceeds maximum path size or unable to convert */
906 continue;
907 }
908 path = strdup(platform);
909 jplis_assert(path != (char*)NULL)JPLISAssertCondition((jboolean)(path != (char*)((void*)0)), "path != (char*)NULL"
, "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 909)
;
910 }
911
912 /*
913 * Post-process the URI path - needed on Windows to transform
914 * /c:/foo to c:/foo.
915 */
916 TRANSFORM(path, fromURIPath(path)){ char* tmp = fromURIPath(path); if (tmp != path) { free(path
); path = tmp; } JPLISAssertCondition((jboolean)((void*)path !=
(void*)((void*)0)), "(void*)path != (void*)NULL", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 916); }
;
917
918 /*
919 * Normalize the path - no duplicate slashes (except UNCs on Windows), trailing
920 * slash removed.
921 */
922 TRANSFORM(path, normalize(path)){ char* tmp = normalize(path); if (tmp != path) { free(path);
path = tmp; } JPLISAssertCondition((jboolean)((void*)path !=
(void*)((void*)0)), "(void*)path != (void*)NULL", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 922); }
;
923
924 /*
925 * If the path is an absolute path then add to the bootclassloader
926 * search path. Otherwise we get the canonical path of the agent jar
927 * and then use its base path (directory) to resolve the given path
928 * segment.
929 *
930 * NOTE: JVMTI is specified to use modified UTF8 strings (like JNI).
931 * In 1.5.0 the AddToBootstrapClassLoaderSearch takes a platform string
932 * - see 5049313.
933 */
934 if (isAbsolute(path)) {
935 jvmtierr = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, path);
936 } else {
937 char* resolved;
938
939 if (!haveBasePath) {
940 if (JDK_Canonicalize((char*)jarfile, canonicalPath, sizeof(canonicalPath)) != 0) {
941 fprintf(stderr, "WARNING: unable to canonicalize %s\n", jarfile)__fprintf_chk (stderr, 2 - 1, "WARNING: unable to canonicalize %s\n"
, jarfile)
;
942 free(path);
943 continue;
944 }
945 parent = basePath(canonicalPath);
946 jplis_assert(parent != (char*)NULL)JPLISAssertCondition((jboolean)(parent != (char*)((void*)0)),
"parent != (char*)NULL", "/home/daniel/Projects/java/jdk/src/java.instrument/share/native/libinstrument/InvocationAdapter.c"
, 946)
;
947 haveBasePath = 1;
948 }
949
950 resolved = resolve(parent, path);
951 jvmtierr = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, resolved);
952 free(resolved);
953 }
954
955 /* print warning if boot class path not updated */
956 if (jvmtierr != JVMTI_ERROR_NONE) {
957 check_phase_blob_ret(jvmtierr, free(path))if ((jvmtierr) == JVMTI_ERROR_WRONG_PHASE) { free(path); return
; }
;
958
959 fprintf(stderr, "WARNING: %s not added to bootstrap class loader search: ", path)__fprintf_chk (stderr, 2 - 1, "WARNING: %s not added to bootstrap class loader search: "
, path)
;
960 switch (jvmtierr) {
961 case JVMTI_ERROR_ILLEGAL_ARGUMENT :
962 fprintf(stderr, "Illegal argument or not JAR file\n")__fprintf_chk (stderr, 2 - 1, "Illegal argument or not JAR file\n"
)
;
963 break;
964 default:
965 fprintf(stderr, "Unexpected error: %d\n", jvmtierr)__fprintf_chk (stderr, 2 - 1, "Unexpected error: %d\n", jvmtierr
)
;
966 }
967 }
968
969 /* finished with the path */
970 free(path);
971 }
972
973
974 /* clean-up */
975 if (haveBasePath && parent != canonicalPath) {
976 free(parent);
977 }
978 free(paths);
979}