1 /*
2 * Copyright (c) 1998, 2020, 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 #include "java.h"
27 #include "jvm_md.h"
28 #include <dirent.h>
29 #include <dlfcn.h>
30 #include <fcntl.h>
31 #include <inttypes.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #ifdef __DragonFly__
39 #include <sys/sysctl.h>
40 #endif
41 #ifdef __FreeBSD__
42 #include <sys/sysctl.h>
43 #include <sys/procctl.h>
44 #ifndef PROC_STACKGAP_DISABLE
45 #define PROC_STACKGAP_DISABLE 0x0002
46 #endif
47 #ifndef PROC_STACKGAP_CTL
48 #define PROC_STACKGAP_CTL 17
49 #endif
50 #endif /* __FreeBSD__ */
51 #include "manifest_info.h"
52
53
54 #define JVM_DLL "libjvm.so"
55 #define JAVA_DLL "libjava.so"
56 #ifdef AIX
57 #define LD_LIBRARY_PATH "LIBPATH"
58 #else
59 #define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
60 #endif
61
62 /* help jettison the LD_LIBRARY_PATH settings in the future */
63 #ifndef SETENV_REQUIRED
64 #define SETENV_REQUIRED
65 #endif
66
67 /*
68 * Flowchart of launcher execs and options processing on unix
69 *
70 * The selection of the proper vm shared library to open depends on
71 * several classes of command line options, including vm "flavor"
72 * options (-client, -server).
73 * The vm selection options are not passed to the running
74 * virtual machine; they must be screened out by the launcher.
75 *
76 * The version specification (if any) is processed first by the
77 * platform independent routine SelectVersion. This may result in
78 * the exec of the specified launcher version.
79 *
80 * Previously the launcher modified the LD_LIBRARY_PATH appropriately for the
81 * desired data model path, regardless if data models matched or not. The
82 * launcher subsequently exec'ed the desired executable, in order to make the
83 * LD_LIBRARY_PATH path available, for the runtime linker.
84 *
85 * Now, in most cases,the launcher will dlopen the target libjvm.so. All
86 * required libraries are loaded by the runtime linker, using the
87 * $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore,
88 * in most cases, the launcher will only exec, if the data models are
89 * mismatched, and will not set any environment variables, regardless of the
90 * data models.
91 *
92 * However, if the environment contains a LD_LIBRARY_PATH, this will cause the
93 * launcher to inspect the LD_LIBRARY_PATH. The launcher will check
94 * a. if the LD_LIBRARY_PATH's first component is the path to the desired
95 * libjvm.so
96 * b. if any other libjvm.so is found in any of the paths.
97 * If case b is true, then the launcher will set the LD_LIBRARY_PATH to the
98 * desired JRE and reexec, in order to propagate the environment.
99 *
100 * Main
101 * (incoming argv)
102 * |
103 * \|/
104 * CreateExecutionEnvironment
105 * (determines desired data model)
106 * |
107 * |
108 * \|/
109 * Have Desired Model ? --> NO --> Exit(with error)
110 * |
111 * |
112 * \|/
113 * YES
114 * |
115 * |
116 * \|/
117 * CheckJvmType
118 * (removes -client, -server, etc.)
119 * |
120 * |
121 * \|/
122 * TranslateDashJArgs...
123 * (Prepare to pass args to vm)
124 * |
125 * |
126 * \|/
127 * ParseArguments
128 * |
129 * |
130 * \|/
131 * RequiresSetenv
132 * Is LD_LIBRARY_PATH
133 * and friends set ? --> NO --> Continue
134 * YES
135 * |
136 * |
137 * \|/
138 * Path is desired JRE ? YES --> Continue
139 * NO
140 * |
141 * |
142 * \|/
143 * Paths have well known
144 * jvm paths ? --> NO --> Error/Exit
145 * YES
146 * |
147 * |
148 * \|/
149 * Does libjvm.so exist
150 * in any of them ? --> NO --> Continue
151 * YES
152 * |
153 * |
154 * \|/
155 * Set the LD_LIBRARY_PATH
156 * |
157 * |
158 * \|/
159 * Re-exec
160 * |
161 * |
162 * \|/
163 * Main
164 */
165
166 /* Store the name of the executable once computed */
167 static char *execname = NULL;
168
169 /*
170 * execname accessor from other parts of platform dependent logic
171 */
172 const char *
GetExecName()173 GetExecName() {
174 return execname;
175 }
176
177 #ifdef SETENV_REQUIRED
178 static jboolean
JvmExists(const char * path)179 JvmExists(const char *path) {
180 char tmp[PATH_MAX + 1];
181 struct stat statbuf;
182 JLI_Snprintf(tmp, PATH_MAX, "%s/%s", path, JVM_DLL);
183 if (stat(tmp, &statbuf) == 0) {
184 return JNI_TRUE;
185 }
186 return JNI_FALSE;
187 }
188 /*
189 * contains a lib/{server,client}/libjvm.so ?
190 */
191 static jboolean
ContainsLibJVM(const char * env)192 ContainsLibJVM(const char *env) {
193 /* the usual suspects */
194 char clientPattern[] = "lib/client";
195 char serverPattern[] = "lib/server";
196 char *envpath;
197 char *path;
198 char* save_ptr = NULL;
199 jboolean clientPatternFound;
200 jboolean serverPatternFound;
201
202 /* fastest path */
203 if (env == NULL) {
204 return JNI_FALSE;
205 }
206
207 /* to optimize for time, test if any of our usual suspects are present. */
208 clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
209 serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
210 if (clientPatternFound == JNI_FALSE && serverPatternFound == JNI_FALSE) {
211 return JNI_FALSE;
212 }
213
214 /*
215 * we have a suspicious path component, check if it contains a libjvm.so
216 */
217 envpath = JLI_StringDup(env);
218 for (path = strtok_r(envpath, ":", &save_ptr); path != NULL; path = strtok_r(NULL, ":", &save_ptr)) {
219 if (clientPatternFound && JLI_StrStr(path, clientPattern) != NULL) {
220 if (JvmExists(path)) {
221 JLI_MemFree(envpath);
222 return JNI_TRUE;
223 }
224 }
225 if (serverPatternFound && JLI_StrStr(path, serverPattern) != NULL) {
226 if (JvmExists(path)) {
227 JLI_MemFree(envpath);
228 return JNI_TRUE;
229 }
230 }
231 }
232 JLI_MemFree(envpath);
233 return JNI_FALSE;
234 }
235
236 /*
237 * Test whether the environment variable needs to be set, see flowchart.
238 */
239 static jboolean
RequiresSetenv(const char * jvmpath)240 RequiresSetenv(const char *jvmpath) {
241 char jpath[PATH_MAX + 1];
242 char *llp;
243 char *dmllp = NULL;
244 char *p; /* a utility pointer */
245
246 #ifdef MUSL_LIBC
247 /*
248 * The musl library loader requires LD_LIBRARY_PATH to be set in order
249 * to correctly resolve the dependency libjava.so has on libjvm.so.
250 */
251 return JNI_TRUE;
252 #endif
253
254 #ifdef AIX
255 /* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */
256 return JNI_TRUE;
257 #endif
258
259 llp = getenv("LD_LIBRARY_PATH");
260 /* no environment variable is a good environment variable */
261 if (llp == NULL && dmllp == NULL) {
262 return JNI_FALSE;
263 }
264 #ifdef __linux
265 /*
266 * On linux, if a binary is running as sgid or suid, glibc sets
267 * LD_LIBRARY_PATH to the empty string for security purposes. (In contrast,
268 * on Solaris the LD_LIBRARY_PATH variable for a privileged binary does not
269 * lose its settings; but the dynamic linker does apply more scrutiny to the
270 * path.) The launcher uses the value of LD_LIBRARY_PATH to prevent an exec
271 * loop, here and further downstream. Therefore, if we are running sgid or
272 * suid, this function's setting of LD_LIBRARY_PATH will be ineffective and
273 * we should case a return from the calling function. Getting the right
274 * libraries will be handled by the RPATH. In reality, this check is
275 * redundant, as the previous check for a non-null LD_LIBRARY_PATH will
276 * return back to the calling function forthwith, it is left here to safe
277 * guard against any changes, in the glibc's existing security policy.
278 */
279 if ((getgid() != getegid()) || (getuid() != geteuid())) {
280 return JNI_FALSE;
281 }
282 #endif /* __linux */
283
284 #ifdef _BSDONLY_SOURCE
285 /*
286 * The BSD's (except MacOSX which doesn't include this file), also clear
287 * LD_LIBRARY_PATH when a binary is running setuid or setgid.
288 */
289 if (issetugid()) {
290 return JNI_FALSE;
291 }
292 #endif /* _BSDONLY_SOURCE */
293
294 /*
295 * Prevent recursions. Since LD_LIBRARY_PATH is the one which will be set by
296 * previous versions of the JRE, thus it is the only path that matters here.
297 * So we check to see if the desired JRE is set.
298 */
299 JLI_StrNCpy(jpath, jvmpath, PATH_MAX);
300 p = JLI_StrRChr(jpath, '/');
301 *p = '\0';
302 if (llp != NULL && JLI_StrNCmp(llp, jpath, JLI_StrLen(jpath)) == 0) {
303 return JNI_FALSE;
304 }
305
306 /* scrutinize all the paths further */
307 if (llp != NULL && ContainsLibJVM(llp)) {
308 return JNI_TRUE;
309 }
310 if (dmllp != NULL && ContainsLibJVM(dmllp)) {
311 return JNI_TRUE;
312 }
313 return JNI_FALSE;
314 }
315 #endif /* SETENV_REQUIRED */
316
317 void
CreateExecutionEnvironment(int * pargc,char *** pargv,char jrepath[],jint so_jrepath,char jvmpath[],jint so_jvmpath,char jvmcfg[],jint so_jvmcfg)318 CreateExecutionEnvironment(int *pargc, char ***pargv,
319 char jrepath[], jint so_jrepath,
320 char jvmpath[], jint so_jvmpath,
321 char jvmcfg[], jint so_jvmcfg) {
322
323 char * jvmtype = NULL;
324 int argc = *pargc;
325 char **argv = *pargv;
326
327 #ifdef SETENV_REQUIRED
328 jboolean mustsetenv = JNI_FALSE;
329 char *runpath = NULL; /* existing effective LD_LIBRARY_PATH setting */
330 char* new_runpath = NULL; /* desired new LD_LIBRARY_PATH string */
331 char* newpath = NULL; /* path on new LD_LIBRARY_PATH */
332 char* lastslash = NULL;
333 char** newenvp = NULL; /* current environment */
334 size_t new_runpath_size;
335 #endif /* SETENV_REQUIRED */
336
337 /* Compute/set the name of the executable */
338 SetExecname(*pargv);
339
340 /* Check to see if the jvmpath exists */
341 /* Find out where the JRE is that we will be using. */
342 if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE)) {
343 JLI_ReportErrorMessage(JRE_ERROR1);
344 exit(2);
345 }
346 JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
347 jrepath, FILESEP, FILESEP);
348 /* Find the specified JVM type */
349 if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
350 JLI_ReportErrorMessage(CFG_ERROR7);
351 exit(1);
352 }
353
354 jvmpath[0] = '\0';
355 jvmtype = CheckJvmType(pargc, pargv, JNI_FALSE);
356 if (JLI_StrCmp(jvmtype, "ERROR") == 0) {
357 JLI_ReportErrorMessage(CFG_ERROR9);
358 exit(4);
359 }
360
361 if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath)) {
362 JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
363 exit(4);
364 }
365 /*
366 * we seem to have everything we need, so without further ado
367 * we return back, otherwise proceed to set the environment.
368 */
369 #ifdef SETENV_REQUIRED
370 mustsetenv = RequiresSetenv(jvmpath);
371 JLI_TraceLauncher("mustsetenv: %s\n", mustsetenv ? "TRUE" : "FALSE");
372
373 if (mustsetenv == JNI_FALSE) {
374 return;
375 }
376 #else
377 return;
378 #endif /* SETENV_REQUIRED */
379
380 #ifdef SETENV_REQUIRED
381 if (mustsetenv) {
382 /*
383 * We will set the LD_LIBRARY_PATH as follows:
384 *
385 * o $JVMPATH (directory portion only)
386 * o $JRE/lib
387 * o $JRE/../lib
388 *
389 * followed by the user's previous effective LD_LIBRARY_PATH, if
390 * any.
391 */
392
393 runpath = getenv(LD_LIBRARY_PATH);
394
395 /* runpath contains current effective LD_LIBRARY_PATH setting */
396 { /* New scope to declare local variable */
397 char *new_jvmpath = JLI_StringDup(jvmpath);
398 new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
399 2 * JLI_StrLen(jrepath) +
400 JLI_StrLen(new_jvmpath) + 52;
401 new_runpath = JLI_MemAlloc(new_runpath_size);
402 newpath = new_runpath + JLI_StrLen(LD_LIBRARY_PATH "=");
403
404
405 /*
406 * Create desired LD_LIBRARY_PATH value for target data model.
407 */
408 {
409 /* remove the name of the .so from the JVM path */
410 lastslash = JLI_StrRChr(new_jvmpath, '/');
411 if (lastslash)
412 *lastslash = '\0';
413
414 sprintf(new_runpath, LD_LIBRARY_PATH "="
415 "%s:"
416 "%s/lib:"
417 "%s/../lib",
418 new_jvmpath,
419 jrepath,
420 jrepath
421 );
422
423 JLI_MemFree(new_jvmpath);
424
425 /*
426 * Check to make sure that the prefix of the current path is the
427 * desired environment variable setting, though the RequiresSetenv
428 * checks if the desired runpath exists, this logic does a more
429 * comprehensive check.
430 */
431 if (runpath != NULL &&
432 JLI_StrNCmp(newpath, runpath, JLI_StrLen(newpath)) == 0 &&
433 (runpath[JLI_StrLen(newpath)] == 0 ||
434 runpath[JLI_StrLen(newpath)] == ':')) {
435 JLI_MemFree(new_runpath);
436 return;
437 }
438 }
439 }
440
441 /*
442 * Place the desired environment setting onto the prefix of
443 * LD_LIBRARY_PATH. Note that this prevents any possible infinite
444 * loop of execv() because we test for the prefix, above.
445 */
446 if (runpath != 0) {
447 /* ensure storage for runpath + colon + NULL */
448 if ((JLI_StrLen(runpath) + 1 + 1) > new_runpath_size) {
449 JLI_ReportErrorMessageSys(JRE_ERROR11);
450 exit(1);
451 }
452 JLI_StrCat(new_runpath, ":");
453 JLI_StrCat(new_runpath, runpath);
454 }
455
456 if (putenv(new_runpath) != 0) {
457 /* problem allocating memory; LD_LIBRARY_PATH not set properly */
458 exit(1);
459 }
460
461 /*
462 * Unix systems document that they look at LD_LIBRARY_PATH only
463 * once at startup, so we have to re-exec the current executable
464 * to get the changed environment variable to have an effect.
465 */
466
467 newenvp = environ;
468 }
469 #endif /* SETENV_REQUIRED */
470 {
471 char *newexec = execname;
472 JLI_TraceLauncher("TRACER_MARKER:About to EXEC\n");
473 (void) fflush(stdout);
474 (void) fflush(stderr);
475 #ifdef SETENV_REQUIRED
476 if (mustsetenv) {
477 execve(newexec, argv, newenvp);
478 } else {
479 execv(newexec, argv);
480 }
481 #else /* !SETENV_REQUIRED */
482 execv(newexec, argv);
483 #endif /* SETENV_REQUIRED */
484 JLI_ReportErrorMessageSys(JRE_ERROR4, newexec);
485 }
486 exit(1);
487 }
488
489
490 static jboolean
GetJVMPath(const char * jrepath,const char * jvmtype,char * jvmpath,jint jvmpathsize)491 GetJVMPath(const char *jrepath, const char *jvmtype,
492 char *jvmpath, jint jvmpathsize)
493 {
494 struct stat s;
495
496 if (JLI_StrChr(jvmtype, '/')) {
497 JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
498 } else {
499 JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
500 }
501
502 JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
503
504 if (stat(jvmpath, &s) == 0) {
505 JLI_TraceLauncher("yes.\n");
506 return JNI_TRUE;
507 } else {
508 JLI_TraceLauncher("no.\n");
509 return JNI_FALSE;
510 }
511 }
512
513 /*
514 * Find path to JRE based on .exe's location or registry settings.
515 */
516 static jboolean
GetJREPath(char * path,jint pathsize,jboolean speculative)517 GetJREPath(char *path, jint pathsize, jboolean speculative)
518 {
519 char libjava[MAXPATHLEN];
520 struct stat s;
521
522 if (GetApplicationHome(path, pathsize)) {
523 /* Is JRE co-located with the application? */
524 JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
525 if (access(libjava, F_OK) == 0) {
526 JLI_TraceLauncher("JRE path is %s\n", path);
527 return JNI_TRUE;
528 }
529 /* ensure storage for path + /jre + NULL */
530 if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
531 JLI_TraceLauncher("Insufficient space to store JRE path\n");
532 return JNI_FALSE;
533 }
534 /* Does the app ship a private JRE in <apphome>/jre directory? */
535 JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
536 if (access(libjava, F_OK) == 0) {
537 JLI_StrCat(path, "/jre");
538 JLI_TraceLauncher("JRE path is %s\n", path);
539 return JNI_TRUE;
540 }
541 }
542
543 if (GetApplicationHomeFromDll(path, pathsize)) {
544 JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
545 if (stat(libjava, &s) == 0) {
546 JLI_TraceLauncher("JRE path is %s\n", path);
547 return JNI_TRUE;
548 }
549 }
550
551 if (!speculative)
552 JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
553 return JNI_FALSE;
554 }
555
556 jboolean
LoadJavaVM(const char * jvmpath,InvocationFunctions * ifn)557 LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
558 {
559 void *libjvm;
560
561 JLI_TraceLauncher("JVM path is %s\n", jvmpath);
562
563 libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
564 if (libjvm == NULL) {
565 JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
566 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
567 return JNI_FALSE;
568 }
569
570 ifn->CreateJavaVM = (CreateJavaVM_t)
571 dlsym(libjvm, "JNI_CreateJavaVM");
572 if (ifn->CreateJavaVM == NULL) {
573 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
574 return JNI_FALSE;
575 }
576
577 ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t)
578 dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
579 if (ifn->GetDefaultJavaVMInitArgs == NULL) {
580 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
581 return JNI_FALSE;
582 }
583
584 ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t)
585 dlsym(libjvm, "JNI_GetCreatedJavaVMs");
586 if (ifn->GetCreatedJavaVMs == NULL) {
587 JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
588 return JNI_FALSE;
589 }
590
591 return JNI_TRUE;
592 }
593
594 /*
595 * Compute the name of the executable
596 *
597 * In order to re-exec securely we need the absolute path of the
598 * executable. On Solaris getexecname(3c) may not return an absolute
599 * path so we use dladdr to get the filename of the executable and
600 * then use realpath to derive an absolute path. From Solaris 9
601 * onwards the filename returned in DL_info structure from dladdr is
602 * an absolute pathname so technically realpath isn't required.
603 * On Linux we read the executable name from /proc/self/exe.
604 * On FreeBSD, we get the executable name via sysctl(3).
605 * As a fallback, and for platforms other than Solaris, Linux, and
606 * FreeBSD we use FindExecName to compute the executable name.
607 */
608 const char*
SetExecname(char ** argv)609 SetExecname(char **argv)
610 {
611 char* exec_path = NULL;
612 #if defined(__linux__)
613 {
614 const char* self = "/proc/self/exe";
615 char buf[PATH_MAX+1];
616 int len = readlink(self, buf, PATH_MAX);
617 if (len >= 0) {
618 buf[len] = '\0'; /* readlink(2) doesn't NUL terminate */
619 exec_path = JLI_StringDup(buf);
620 }
621 }
622 #elif defined(__FreeBSD__) || defined(__DragonFly__)
623 {
624 char buf[PATH_MAX+1];
625 int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
626 size_t len = sizeof(buf);
627 if (sysctl(name, 4, buf, &len, NULL, 0) == 0 && len > 0) {
628 buf[len] = '\0';
629 exec_path = JLI_StringDup(buf);
630 }
631 }
632 #else /* !__linux__ && !__FreeBSD__ */
633 {
634 /* Not implemented */
635 }
636 #endif
637
638 if (exec_path == NULL) {
639 exec_path = FindExecName(argv[0]);
640 }
641 execname = exec_path;
642 return exec_path;
643 }
644
645 /* --- Splash Screen shared library support --- */
646 static const char* SPLASHSCREEN_SO = JNI_LIB_NAME("splashscreen");
647 static void* hSplashLib = NULL;
648
SplashProcAddress(const char * name)649 void* SplashProcAddress(const char* name) {
650 if (!hSplashLib) {
651 int ret;
652 char jrePath[MAXPATHLEN];
653 char splashPath[MAXPATHLEN];
654
655 if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
656 JLI_ReportErrorMessage(JRE_ERROR1);
657 return NULL;
658 }
659 ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",
660 jrePath, SPLASHSCREEN_SO);
661
662 if (ret >= (int) sizeof(splashPath)) {
663 JLI_ReportErrorMessage(JRE_ERROR11);
664 return NULL;
665 }
666 if (ret < 0) {
667 JLI_ReportErrorMessage(JRE_ERROR13);
668 return NULL;
669 }
670 hSplashLib = dlopen(splashPath, RTLD_LAZY | RTLD_GLOBAL);
671 JLI_TraceLauncher("Info: loaded %s\n", splashPath);
672 }
673 if (hSplashLib) {
674 void* sym = dlsym(hSplashLib, name);
675 return sym;
676 } else {
677 return NULL;
678 }
679 }
680
681 /*
682 * Signature adapter for pthread_create() or thr_create().
683 */
ThreadJavaMain(void * args)684 static void* ThreadJavaMain(void* args) {
685 return (void*)(intptr_t)JavaMain(args);
686 }
687
688 /*
689 * Block current thread and continue execution in a new thread.
690 */
691 int
CallJavaMainInNewThread(jlong stack_size,void * args)692 CallJavaMainInNewThread(jlong stack_size, void* args) {
693 int rslt;
694 pthread_t tid;
695 pthread_attr_t attr;
696 pthread_attr_init(&attr);
697 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
698
699 if (stack_size > 0) {
700 pthread_attr_setstacksize(&attr, stack_size);
701 }
702 pthread_attr_setguardsize(&attr, 0); // no pthread guard page on java threads
703
704 if (pthread_create(&tid, &attr, ThreadJavaMain, args) == 0) {
705 void* tmp;
706 pthread_join(tid, &tmp);
707 rslt = (int)(intptr_t)tmp;
708 } else {
709 /*
710 * Continue execution in current thread if for some reason (e.g. out of
711 * memory/LWP) a new thread can't be created. This will likely fail
712 * later in JavaMain as JNI_CreateJavaVM needs to create quite a
713 * few new threads, anyway, just give it a try..
714 */
715 rslt = JavaMain(args);
716 }
717
718 pthread_attr_destroy(&attr);
719 return rslt;
720 }
721
722 /* Coarse estimation of number of digits assuming the worst case is a 64-bit pid. */
723 #define MAX_PID_STR_SZ 20
724
725 int
JVMInit(InvocationFunctions * ifn,jlong threadStackSize,int argc,char ** argv,int mode,char * what,int ret)726 JVMInit(InvocationFunctions* ifn, jlong threadStackSize,
727 int argc, char **argv,
728 int mode, char *what, int ret)
729 {
730 #ifdef __FreeBSD__
731 /*
732 * Kernel stack guard pages interfere with the JVM's guard pages on the
733 * thread stacks and prevent correct stack overflow detection and the
734 * use of reserved pages to allow critical sections to complete.
735 *
736 * Attempt to disable the kernel stack guard pages here before any threads
737 * are created.
738 */
739 int arg = PROC_STACKGAP_DISABLE;
740 procctl(P_PID, getpid(), PROC_STACKGAP_CTL, &arg);
741 #endif
742 ShowSplashScreen();
743 return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
744 }
745
746 void
PostJVMInit(JNIEnv * env,jclass mainClass,JavaVM * vm)747 PostJVMInit(JNIEnv *env, jclass mainClass, JavaVM *vm)
748 {
749 // stubbed out for windows and *nixes.
750 }
751
752 void
RegisterThread()753 RegisterThread()
754 {
755 // stubbed out for windows and *nixes.
756 }
757
758 /*
759 * on unix, we return a false to indicate this option is not applicable
760 */
761 jboolean
ProcessPlatformOption(const char * arg)762 ProcessPlatformOption(const char *arg)
763 {
764 return JNI_FALSE;
765 }
766