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