Fix for test/jdk/tools/jpackage/share/JavaOptionsTest.java on Alpine Linux
Alexander Scherbatiy
alexander.scherbatiy at bell-sw.com
Thu Feb 20 13:29:38 UTC 2020
Hello,
Short description:
JavaOptionsTest.java test creates a jar file with a simple Hello java
class, packages it into a native app and calls it.
JLI reexecutes the native app on Linux Alpine and because of this java
options are doubled when passed to Hello application.
The proposed fix adds java options only if the application arguments
does not contain them:
http://cr.openjdk.java.net/~alexsch/portola/tests/jpackage/webrev.01
Detailed description:
The native app first calls start_launcher() method from
src/jdk.incubator.jpackage/share/native/libapplauncher/main.cpp file
which uses Package::SetCommandLineArguments() to store provided
arguments in FBootFields->FArgs field. Next it calls RunVM().
JavaVirtualMachine::launchVM() method stores both java options and
arguments from FBootFields->FArgs into jvm args list and calls
javaLibrary.JavaVMCreate() so the provided args are passed to the java
application.
This path is different on Alpine Linux which sets LD_LIBRARY_PATH and
JLI decides to invoke start_launcher() one more time with the updated
library path (see [1]).
This time all java options are passed to start_launcher() method, they
stored in FBootFields->FArgs and concatenated with java options passed
to JavaVirtualMachine::launchVM() method.
So jvm options are stored twice in case the launcher decides to reexec
itself.
Possible solutions:
1. The right way would be to detect that the JLI is reexecuted in the
same way as it does JLI (see [2]). It has some complicated logic in
ContainsLibJVM() method and the code needs to be shared between
java.base and jdk.incubator.jpackage modules.
2. Using a static variable to check that the jpackage is executed the
second time. It does not work because the jpackage is executed by as a
new process by execve().
Here are two subsequent calls of execve() on Alpine Linux from strace log:
-----
execve("./output/test/bin/test", ["./output/test/bin/test",
"-Dparam2=test2"], 0x7fff98259778 /* 8 vars */) = 0
execve("/root/mount/repos/branch-portola-dev/jtreg/alpine/app/output/test/bin/test",
["./output/test/bin/test", "-Djava.library.path=/root/mount/"..., "-Djava.l
arch_prctl(ARCH_SET_FS, 0x7f42a0298d48) = 0
-----
Java options are passed to the second app call there jpackage adds them
one more time.
3. Check in some way that the app arguments already contain java options
and to not add them the second time.
The proposed fix converts the app arguments to std::set. I tried to use
std::unordered_set but got the error message:
"#error This file requires compiler and library support for the ISO C++
2011 standard. This support must be enabled with the -std=c++11 or
-std=gnu++11 compiler options."
Actually java options are always set first for vmargs so it is also
possible only to check that if the app arguments list starts with java
options list. It relies on the way how java options are passed to
jpackage and it can be fragile.
May be it has sense to check the app arguments and java options only if
LIBC is defined and it equals to musl.
One more interesting question is if the test passes on AIX because AIX
also requires the modified LD_LIBRARY_PATH and the test should fail for
the same reason.
[1]
https://hg.openjdk.java.net/portola/portola/file/7ff60204a181/src/java.base/unix/native/libjli/java_md_solinux.c#l85
[2]
https://hg.openjdk.java.net/portola/portola/file/7ff60204a181/src/java.base/unix/native/libjli/java_md_solinux.c#l306
Thanks,
Alexander.
More information about the portola-dev
mailing list