RFD: What do we do about programs which set sys_paths to null?
Langer, Christoph
christoph.langer at sap.com
Fri Mar 20 10:40:51 UTC 2020
Hi Andrew,
to me this looks like a good and feasible solution to restore old behavior while still keeping Runtime::load and Runtime::loadLibrary free from deadlock-prone synchronization.
Can you create a JBS bug for this and set it to 11-pool?
I'll run your fix through some regression testing in 11u. There we haven't backed out JDK-8231584 yet.
Best regards
Christoph
> -----Original Message-----
> From: jdk-updates-dev <jdk-updates-dev-bounces at openjdk.java.net> On
> Behalf Of Andrew Haley
> Sent: Dienstag, 17. März 2020 17:50
> To: jdk-updates-dev at openjdk.java.net; jdk8u-dev at openjdk.java.net
> Subject: RFD: What do we do about programs which set sys_paths to null?
>
> [ People who know all this stuff already, please feel free to skip
> this introduction. ]
>
> This is a request for discussion about support for some programs that
> do something illegal, not at all supported. I'd like to make this work
> as intended by users, even though it's unsupported. Which seems odd,
> but I still think we should do it.
>
> There is a long-established hack (going back about 20 years) which
> allows Java programs to set the property "java.library.path"
> dynamically. You might need to do this if you're a Java program which
> extracts a shared library from a jarfile, puts it in a tmpdir
> somewhere, then loads that library.
>
> People discovered that even though you can set "java.library.path" in
> a program, it doesn't work as intended because the property is only
> read once at boot time, and it is then cached in the static field
> ClassLoader.usr_paths. So, people discovered that if they set
> "java.library.path" then set set ClassLoader.sys_paths to null, then
> called ClassLoader.loadLibrary, it works. Something like this:
>
> Class loaderClass = ClassLoader.class;
> Field userPaths = loaderClass.getDeclaredField( "sys_paths" );
> userPaths.setAccessible( true );
> userPaths.set( null, null );
>
> See the answer here, for example:
> https://community.oracle.com/thread/1551225?start=15&tstart=0
>
> This worked because ClassLoader.loadLibrary() did this:
>
> if (sys_paths == null) {
> usr_paths = initializePath("java.library.path");
> sys_paths = initializePath("sun.boot.library.path");
> }
>
> The paths got re-initialized.
>
> The back-ported fix for "8231584: Deadlock with
> ClassLoader.findLibrary and System.loadLibrary call", broke this
> hack. The code that lazily re-initializes usr_paths and sys_paths has
> gone. However, there was another important change:
> ClassLoader.loadLibrary0(), which calls ClassLoader.loadLibrary, is no
> longer synchronized, so there may now be concurrent accesses to
> ClassLoader.loadLibrary().
>
> [ The proposed fix. ]
>
> I'd like to add this patch to 8u and 11u:
>
> --- a/src/java.base/share/classes/java/lang/ClassLoader.java Mon Feb 03
> 09:39:39 2020 +0100
> +++ b/src/java.base/share/classes/java/lang/ClassLoader.java Tue Mar 17
> 16:24:10 2020 +0000
> @@ -2562,7 +2562,7 @@
>
> // The paths searched for libraries
> private static String usr_paths[];
> - private static String sys_paths[];
> + private static volatile String sys_paths[];
>
> private static String[] initializePath(String propName) {
> String ldPath = System.getProperty(propName, "");
> @@ -2620,6 +2620,10 @@
> boolean isAbsolute) {
> ClassLoader loader =
> (fromClass == null) ? null : fromClass.getClassLoader();
> + if (sys_paths == null) {
> + usr_paths = initializePath("java.library.path");
> + sys_paths = initializePath("sun.boot.library.path");
> + }
> assert sys_paths != null : "should be initialized at this point";
> assert usr_paths != null : "should be initialized at this point";
>
> This patch does nothing unless sys_paths has been set to null. There
> is some slight slowdown because a non-volatile read of sys_paths is
> now volatile, but it's IMO insignificant and in any case it's less
> than the overhead of the synchronized loadLibrary0().
>
> I do not believe that this introduces a race when the user sets
> sys_paths to null because
>
> setProperty("java.library.path") happens before (write volatile sys_paths)
> (Program order)
> (write volatile sys_paths) synchronizes with (read volatile sys_paths)
> (read volatile sys_paths) happens before getProperty("java.lbrary.path")
> (Program order)
>
> If the user sets sys_paths to null before setting "java.library.path"
> there is indeed a race and their program might not work, but there
> always was a race anyway.
>
> I think we should do this for 8u and 11u. My justification is that even
> though this is an ugly hack, it satisfies a real need and we don't want
> to break users' programs in an update.
>
> What do you think?
>
> --
> Andrew Haley (he/him)
> Java Platform Lead Engineer
> Red Hat UK Ltd. <https://www.redhat.com>
> https://keybase.io/andrewhaley
> EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
More information about the jdk-updates-dev
mailing list