Re: RFR: 8268129: LibraryLookup::ofDefault leaks symbols from loaded libraries

2021-10-07 Thread Cheng Jin
On Wed, 2 Jun 2021 20:13:34 GMT, Maurizio Cimadamore  
wrote:

>> This patch overhauls the library loading mechanism used by the Foreign 
>> Linker API. We realized that, while handy, the *default* lookup abstraction 
>> (`LibraryLookup::ofDefault`) was behaving inconsistentlt across platforms.
>> 
>> This patch replaces `LibraryLookup` with a simpler `SymbolLookup` 
>> abstraction, a functional interface. Crucially, `SymbolLookup` does not 
>> concern with library loading, only symbol lookup. For this reason, two 
>> factories are added:
>> 
>> * `SymbolLookup::loaderLookup` - which obtains a lookup that can be used to 
>> lookup symbols in libraries loaded by current loader
>> * `CLinker::systemLookup` - a more stable replacement for the *default* 
>> lookup, which looks for symbols in libc.so (or its equivalent in other 
>> platforms). The contents of this lookup are unspecified.
>> 
>> Both factories are *restricted*, so they can only be called when 
>> `--enable-native-access` is set.
>
>> _Mailing list message from [Chapman Flack](mailto:c...@anastigmatix.net) on 
>> [security-dev](mailto:security-...@mail.openjdk.java.net):_
>> 
>> On 06/02/21 13:30, Maurizio Cimadamore wrote:
>> 
>> > This patch replaces `LibraryLookup` with a simpler `SymbolLookup`
>> > abstraction, a functional interface. Crucially, `SymbolLookup` does not
>> > concern with library loading, only symbol lookup. For this reason, two
>> > factories are added:
>> 
>> Hi,
>> 
>> While I am thinking about this, what will be the behavior when the JVM
>> itself has been dynamically loaded into an embedding application, and
>> launched with the JNI invocation API?
>> 
>> Will there be a *Lookup flavor that is able to find any exported symbol
>> known in the embedding environment the JVM was loaded into? (This is the
>> sort of condition the Mac OS linker checks when given the -bundle_loader
>> option.)
>> 
>> Regards,
>> Chapman Flack (maintainer of a project that happens to work that way)
> 
> Hi,
> at the moment we don't have plans to add such a lookup, but I believe it 
> should be possible to build such a lookup using `dlopen` and the linker API. 
> I have provided an example elsewhere of how easy it easy to build a wrapper 
> lookup around dlopen/dlsym:
> 
> https://gist.github.com/mcimadamore/0883ea6f4836ae0c1d2a31c48197da1a
> 
> Perhaps something like that could be useful in the use case you mention?

Hi @mcimadamore,

As you mentioned at 
https://github.com/openjdk/jdk/pull/4316#issuecomment-853238872, the system 
lookup is supported by the underlying `NativeLibraries` which also works on 
OpenJDK16 to support `LibraryLookup::ofDefault`.

But my finding is that it `LibraryLookup::ofDefault` works good on AIX (with 
`libc.a`) in OpenJDK16 but `CLinker.systemLookup()` ended up with  
`NoSuchElementException` after changing the code in `SystemLookup.java` and 
`CABI.java` as follows:

private static final SymbolLookup syslookup = switch (CABI.current()) {
case SysV, LinuxAArch64, MacOsAArch64, AIX -> libLookup(libs -> 
libs.loadLibrary("syslookup"));
case Win64 -> makeWindowsLookup(); // out of line to workaround javac 
crash
};

with a simple test & output:

import jdk.incubator.foreign.CLinker;
import static jdk.incubator.foreign.CLinker.*;
import jdk.incubator.foreign.SymbolLookup;
import jdk.incubator.foreign.Addressable;

public class Test {
private static CLinker clinker = CLinker.getInstance();
private static final SymbolLookup defaultLibLookup = 
CLinker.systemLookup();

public static void main(String args[]) throws Throwable {
Addressable strlenSymbol = 
defaultLibLookup.lookup("strlen").get();
}
}

bin/java  --enable-native-access=ALL-UNNAMED  --add-modules 
jdk.incubator.foreign -Dforeign.restricted=permit Test
WARNING: Using incubator modules: jdk.incubator.foreign
Exception in thread "main" java.util.NoSuchElementException: No value present 
<-
at java.base/java.util.Optional.get(Optional.java:143)
at Test.main(Test.java:11)


So I am wondering what happened to the system lookup in such case given there 
should be no fundamental difference in leveraging `NativeLibraries` (I assume 
the library loading in OpenJDK16 & 17 is the same at this point) unless there 
is something else new in OpenJDK17 I am unaware of (e.g. the changes in 
`Lib.gmk` or `lib-std.m4`, or a custom system lookup is required on AIX, etc).  
Thanks.

-

PR: https://git.openjdk.java.net/jdk/pull/4316


Re: RFR: 8268129: LibraryLookup::ofDefault leaks symbols from loaded libraries [v7]

2021-10-12 Thread Cheng Jin
On Thu, 3 Jun 2021 20:49:44 GMT, Maurizio Cimadamore  
wrote:

>> This patch overhauls the library loading mechanism used by the Foreign 
>> Linker API. We realized that, while handy, the *default* lookup abstraction 
>> (`LibraryLookup::ofDefault`) was behaving inconsistentlt across platforms.
>> 
>> This patch replaces `LibraryLookup` with a simpler `SymbolLookup` 
>> abstraction, a functional interface. Crucially, `SymbolLookup` does not 
>> concern with library loading, only symbol lookup. For this reason, two 
>> factories are added:
>> 
>> * `SymbolLookup::loaderLookup` - which obtains a lookup that can be used to 
>> lookup symbols in libraries loaded by current loader
>> * `CLinker::systemLookup` - a more stable replacement for the *default* 
>> lookup, which looks for symbols in libc.so (or its equivalent in other 
>> platforms). The contents of this lookup are unspecified.
>> 
>> Both factories are *restricted*, so they can only be called when 
>> `--enable-native-access` is set.
>
> Maurizio Cimadamore has updated the pull request incrementally with one 
> additional commit since the last revision:
> 
>   Address review comments on shim lib makefile

Just tried with `System.load()` but still ended up with pretty much the same 
failure given both of them eventually invokes `ClassLoader.loadLibrary` to load 
the library in which case there is no big difference at this point.

static {
System.load("/usr/lib/libc.a");
}

Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load 
/usr/lib/libc.a <
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:1793)
at java.base/java.lang.System.load(System.java:672)
at StdLibTest.(StdLibTest.java:24)

-

PR: https://git.openjdk.java.net/jdk/pull/4316


Re: RFR: 8268129: LibraryLookup::ofDefault leaks symbols from loaded libraries

2021-10-12 Thread Cheng Jin
On Tue, 12 Oct 2021 15:04:02 GMT, Maurizio Cimadamore  
wrote:

> Is libc.a loadable on AIX (e.g. with System.loadLibrary) ?

I tried to load `libc.a` and `libc` this way but neither of them works on AIX.
e.g.

public class StdLibTest {
private static CLinker clinker = CLinker.getInstance();
static {
System.loadLibrary("libc.a"); <-
}
private static final SymbolLookup defaultLibLookup = 
SymbolLookup.loaderLookup();

public static void main(String args[]) throws Throwable {
Addressable strlenSymbol = 
defaultLibLookup.lookup("strlen").get();
}
}

$ ./bin/java  --enable-native-access=ALL-UNNAMED  --add-modules 
jdk.incubator.foreign 
-Dforeign.restricted=permit --enable-native-access=ALL-UNNAMED  StdLibTest
WARNING: Using incubator modules: jdk.incubator.foreign
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load libc.a 
<---
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:1822)
at java.base/java.lang.System.loadLibrary(System.java:694)
at StdLibTest.(StdLibTest.java:23)

and 

public class StdLibTest {
private static CLinker clinker = CLinker.getInstance();
static {
System.loadLibrary("libc"); <---
}
private static final SymbolLookup defaultLibLookup = 
SymbolLookup.loaderLookup();

public static void main(String args[]) throws Throwable {
Addressable strlenSymbol = 
defaultLibLookup.lookup("strlen").get();
}
}

$ ./bin/java  --enable-native-access=ALL-UNNAMED  --add-modules 
jdk.incubator.foreign
-Dforeign.restricted=permit --enable-native-access=ALL-UNNAMED  StdLibTest
WARNING: Using incubator modules: jdk.incubator.foreign
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load libc 
<--
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:1822)
at java.base/java.lang.System.loadLibrary(System.java:694)
at StdLibTest.(StdLibTest.java:23)

-

PR: https://git.openjdk.java.net/jdk/pull/4316


Re: RFR: 8268129: LibraryLookup::ofDefault leaks symbols from loaded libraries

2021-10-08 Thread Cheng Jin
On Fri, 8 Oct 2021 21:29:19 GMT, Maurizio Cimadamore  
wrote:

>> Hi @mcimadamore,
>> 
>> As you mentioned at 
>> https://github.com/openjdk/jdk/pull/4316#issuecomment-853238872, the system 
>> lookup is supported by the underlying `NativeLibraries` which also works on 
>> OpenJDK16 to support `LibraryLookup::ofDefault`.
>> 
>> But my finding is that it `LibraryLookup::ofDefault` works good on AIX (with 
>> `libc.a`) in OpenJDK16 but `CLinker.systemLookup()` ended up with  
>> `NoSuchElementException` after changing the code in `SystemLookup.java` and 
>> `CABI.java` as follows:
>> 
>> private static final SymbolLookup syslookup = switch (CABI.current()) {
>> case SysV, LinuxAArch64, MacOsAArch64, AIX -> libLookup(libs -> 
>> libs.loadLibrary("syslookup"));
>> case Win64 -> makeWindowsLookup(); // out of line to workaround 
>> javac crash
>> };
>> 
>> with a simple test & output:
>> 
>> import jdk.incubator.foreign.CLinker;
>> import static jdk.incubator.foreign.CLinker.*;
>> import jdk.incubator.foreign.SymbolLookup;
>> import jdk.incubator.foreign.Addressable;
>> 
>> public class Test {
>> private static CLinker clinker = CLinker.getInstance();
>> private static final SymbolLookup defaultLibLookup = 
>> CLinker.systemLookup();
>> 
>> public static void main(String args[]) throws Throwable {
>> Addressable strlenSymbol = 
>> defaultLibLookup.lookup("strlen").get();
>> }
>> }
>> 
>> bin/java  --enable-native-access=ALL-UNNAMED  --add-modules 
>> jdk.incubator.foreign -Dforeign.restricted=permit Test
>> WARNING: Using incubator modules: jdk.incubator.foreign
>> Exception in thread "main" java.util.NoSuchElementException: No value 
>> present <-
>> at java.base/java.util.Optional.get(Optional.java:143)
>> at Test.main(Test.java:11)
>> 
>> 
>> So I am wondering what happened to the system lookup in such case given 
>> there should be no fundamental difference in leveraging `NativeLibraries` (I 
>> assume the library loading in OpenJDK16 & 17 is the same at this point) 
>> unless there is something else new in OpenJDK17 I am unaware of (e.g. the 
>> changes in `Lib.gmk` or `lib-std.m4`, or a custom system lookup is required 
>> on AIX, etc).  Thanks.
>
>> So I am wondering what happened to the system lookup in such case given 
>> there should be no fundamental difference in leveraging `NativeLibraries` (I 
>> assume the library loading in OpenJDK16 & 17 is the same at this point) 
>> unless there is something else new in OpenJDK17 I am unaware of (e.g. the 
>> changes in `Lib.gmk` or `lib-std.m4`, or a custom system lookup is required 
>> on AIX, etc). Thanks.
> 
> In 17, SystemLookup loads a specific library that is generated at build time 
> - which contains all the c stdlib symbols. That's what the Lib.gmk changes 
> are for. What I suspect is that the library is not generated at all, or not 
> correctly on AIX, which then causes the system lookup to misbehave.
> 
> I would start by double checking that you have a file like this:
> 
> /lib/libsyslookup.so
> 
> And then, if the library exists, check that it has the right dependency; on 
> my linux it's an empty library, but which depends on libc, libm and libdl:
> 
> 
> ldd lib/libsyslookup.so  
>   linux-vdso.so.1 (0x7fff2bdf7000)
>   libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x7f35f1def000)
>   libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x7f35f1ca)
>   libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x7f35f1c9a000)

Hi @mcimadamore,

Here's output of `libsyslookup.so` on AIX:

$ ldd  ./lib/libsyslookup.so
./lib/libsyslookup.so needs:  <--- nothing here

$ whereis libc
libc: /usr/lib/libc.a /usr/lib/libc128.a /usr/ccs/lib/libc.a

So it is high likely that there were no dependencies in this generated library.

> perhaps on AIX something similar to what we did for Windows [1] would be 
> better.

That's what I thought to be the only way around but might need to figure out 
the specifics on AIX.

-

PR: https://git.openjdk.java.net/jdk/pull/4316


Re: RFR: 8268129: LibraryLookup::ofDefault leaks symbols from loaded libraries [v7]

2021-10-12 Thread Cheng Jin
On Thu, 3 Jun 2021 20:49:44 GMT, Maurizio Cimadamore  
wrote:

>> This patch overhauls the library loading mechanism used by the Foreign 
>> Linker API. We realized that, while handy, the *default* lookup abstraction 
>> (`LibraryLookup::ofDefault`) was behaving inconsistentlt across platforms.
>> 
>> This patch replaces `LibraryLookup` with a simpler `SymbolLookup` 
>> abstraction, a functional interface. Crucially, `SymbolLookup` does not 
>> concern with library loading, only symbol lookup. For this reason, two 
>> factories are added:
>> 
>> * `SymbolLookup::loaderLookup` - which obtains a lookup that can be used to 
>> lookup symbols in libraries loaded by current loader
>> * `CLinker::systemLookup` - a more stable replacement for the *default* 
>> lookup, which looks for symbols in libc.so (or its equivalent in other 
>> platforms). The contents of this lookup are unspecified.
>> 
>> Both factories are *restricted*, so they can only be called when 
>> `--enable-native-access` is set.
>
> Maurizio Cimadamore has updated the pull request incrementally with one 
> additional commit since the last revision:
> 
>   Address review comments on shim lib makefile

If so,  I am wondering whether there is anything else left (inherited from 
JDK16) in JDK17 we can leverage to support `libc.a` on AIX except the way 
similar to Windows.

-

PR: https://git.openjdk.java.net/jdk/pull/4316


RE: Incorrect assumption on the class name in compile(InputSource input, String name) at XSLTC.java

2021-11-03 Thread Cheng Jin




The issue for the XSLTC was raised at
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-October/082767.html
:


The code in compile(InputSource input, String name) at
https://github.com/openjdk/jdk/blob/master/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java

seems incorrect as follows:

public boolean compile(InputSource input, String name) {
try {
// Reset globals in case we're called by compile(ArrayList v);
reset();

// The systemId may not be set, so we'll have to check the URL
String systemId = null;
if (input != null) {
systemId = input.getSystemId();
}

// Set the translet class name if not already set
if (_className == null) {
if (name != null) {
setClassName(name);
}
else if (systemId != null && !systemId.equals("")) {
setClassName(Util.baseName(systemId)); <---
incorrect here
}

// Ensure we have a non-empty class name at this point
if (_className == null || _className.length() == 0) {
setClassName("GregorSamsa"); // default translet name
}
}
...

Specifically, the code above assumes that systemId is something like
"xxx:yyy" in which case the class name (_className) is
"die.verwandlung.yyy" ("die.verwandlung." is the default package name since
Java11) However,Util.baseName(systemId) returns null when systemId is
something like "xxx:" (empty after ":"), in which case the class name
(_className) ends up with "die.verwandlung."(an invalid class name inserted
in the constant pool of the generated bytecode).

>From the perspective of robustness, the code above should be updated to
handle the situation. e.g.

else if (systemId != null && !systemId.equals("")) {
  String baseName = Util.baseName(systemId);
 if ((baseName != null) && (baseName.length() > 0))
{ <--
setClassName(baseName);
}

which means it should check whether the returned base name from
Util.baseName(systemId) is empty before setting the class name; otherwise,
it should use the default class name ("GregorSamsa").


Thanks and Best Regards
Cheng Jin

J9 VM, IBM Ottawa Lab at Riverside, Ottawa
IBM Runtime Technologies
+1-613-356-5625
jinch...@ca.ibm.com


Re: Incorrect assumption on the class name in compile(InputSource input, String name) at XSLTC.java

2021-11-03 Thread Cheng Jin




Hi There,

Hotspot developers already identified a bug in verification (failure to
capture an invalid package name "die/verwandlung/" existing in the constant
pool of bytecode) at https://bugs.openjdk.java.net/browse/JDK-8276241 as I
raised via
https://mail.openjdk.java.net/pipermail/hotspot-dev/2021-October/055618.html
, which was associated with the issue here in XSLT transformation given the
invalid package name "die/verwandlung/" was actually triggered by OpenJDK
due to the incorrect result from setClassName(Util.baseName(systemId))
(systemId = "xxx:" in which case Util.baseName(systemId) returns null and
setClassName(null) ended up with "die/verwandlung/" in generating the
bytecode). So I expect someone in OpenJDK to take a look into this issue to
see what really happened to the code there in such case. Thanks.


Thanks and Best Regards
Cheng Jin


Re: Incorrect assumption on the class name in compile(InputSource input, String name) at XSLTC.java

2021-11-04 Thread Cheng Jin





Hi There,

Hotspot developers already identified a bug in verification (failure to
capture an invalid package name "die/verwandlung/" existing in the constant
pool of bytecode) at https://bugs.openjdk.java.net/browse/JDK-8276241 as I
raised via
https://mail.openjdk.java.net/pipermail/hotspot-dev/2021-October/055618.html
, which was associated with the issue here in XSLT transformation given the
invalid package name "die/verwandlung/" was actually triggered by OpenJDK
due to the incorrect result from setClassName(Util.baseName(systemId))
(systemId = "xxx:" in which case Util.baseName(systemId) returns null and
setClassName(null) ended up with "die/verwandlung/" in generating the
bytecode). So I expect someone in OpenJDK to take a look into this issue to
see what really happened to the code there in such case. Thanks.


Thanks and Best Regards
Cheng Jin


Incorrect assumption on the class name in compile(InputSource input, String name) at XSLTC.java

2021-10-23 Thread Cheng Jin




Hi there,

The code in compile(InputSource input, String name) at
https://github.com/openjdk/jdk/blob/master/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java
seems incorrect as follows:

public boolean compile(InputSource input, String name) {
try {
// Reset globals in case we're called by compile(ArrayList v);
reset();

// The systemId may not be set, so we'll have to check the URL
String systemId = null;
if (input != null) {
systemId = input.getSystemId();
}

// Set the translet class name if not already set
if (_className == null) {
if (name != null) {
setClassName(name);
}
else if (systemId != null && !systemId.equals("")) {
setClassName(Util.baseName(systemId)); <---
incorrect here
}

// Ensure we have a non-empty class name at this point
if (_className == null || _className.length() == 0) {
setClassName("GregorSamsa"); // default translet name
}
}
...

Specifically, the code above assumes that systemId is something like
"xxx:yyy" in which case the class name (_className) is
"die.verwandlung.yyy" ("die.verwandlung." is the default package name since
Java11) However,Util.baseName(systemId) returns null when systemId is
something like "xxx:" (empty after ":"), in which case the class name
(_className) ends up with "die.verwandlung."(an invalid class name inserted
in the constant pool of the generated bytecode).

>From the perspective of robustness, the code above should be updated to
handle the situation. e.g.

else if (systemId != null && !systemId.equals("")) {
  String baseName = Util.baseName(systemId);
 if ((baseName != null) && (baseName.length() > 0))
{ <--
setClassName(baseName);
}

which means it should check whether the returned base name from
Util.baseName(systemId) is empty before setting the class name; otherwise,
it should use the default class name ("GregorSamsa").


Let me know if any other concern on this fix.


Thanks and Best Regards
Cheng Jin


Request for backport the OpenJDK fix in XSLTC.java to JDK11 & JDK17

2021-12-09 Thread Cheng Jin



Hi there,

As for the bug with the class name in XSLTC.java I previously raised at
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083135.html
,
I notice it has been resolved at
https://bugs.openjdk.java.net/browse/JDK-8276657 as follows:

https://github.com/openjdk/jdk/blob/a093cdddaf5ab88eb84a147e523db5c3e1be54be/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java

public boolean compile(InputSource input, String name) {
try {
// Reset globals in case we're called by compile(ArrayList v);
reset();

// The systemId may not be set, so we'll have to check the URL
String systemId = null;
if (input != null) {
systemId = input.getSystemId();
}

// Set the translet class name if not already set
if (_className == null) {
if (name != null) {
setClassName(name);
}
else if (systemId != null && !systemId.isEmpty()) { <--
String clsName = Util.baseName(systemId);
if (clsName != null && !clsName.isEmpty()) {
setClassName(clsName);
}
}


With this fix at https://git.openjdk.java.net/jdk/pull/6620, would you
please backport it to JDK11 & JDK17 given the code there is at the same
place? Thanks in advance.


Thanks and Best Regards
Cheng Jin


Please help backport the fix with the XSLT compiler in JDK18 to JDK11 & JDK17

2022-03-07 Thread Cheng Jin
Hi there,

I notice the issue with  the XSLT compiler 
(https://github.com/openjdk/jdk/blob/master/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java)
I raised later last year at 
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-November/083135.html 
has been fixed in JDK18 via  https://bugs.openjdk.java.net/browse/JDK-8276657.
Could you help backport the fix to JDK11 and JDK17 give both of them share the 
same issue in code?  Many thanks.

Best Regards
Cheng Jin


RE: When to initialize the method's class for MethodHandles.Lookup.findStatic()?

2022-03-17 Thread Cheng Jin
Hi Raffaello,

The code snippet I posted previously was not the original test I verified on 
Java 17 (which was generated via asmtools to trigger verification) 

Here's the pretty much the test I used:

Test_1.java
import java.lang.invoke.*;

public class Test_1 {

 static MethodHandle mh;

 static {
 try {
 mh = MethodHandles.lookup().findStatic(Test_2.class,
"testMethod", MethodType.methodType(int[].class));
 } catch (NoSuchMethodException | IllegalAccessException e) {
 e.printStackTrace();
 }
 }

 public static void main(String[] args) throws Throwable {
 //Test_1.mh.invoke();
 }

}

Test_2.jasm
super public class Test_2
version 52:0
{
  static Method "":"()V"
stack 5 locals 12
  {
bipush  -2;
istore  7;
iload   7;
sipush  997;
if_icmplt   L127;
iconst_0;
istore  8;
L127:   stack_frame_type full;
locals_map int, class "[B", class "[B", class 
"[Ljava/lang/Class;", class "[I", class "[I", class "[I", int, bogus, bogus, 
float, float;
iload   8;
istore  8;
return;
  }
  public Method "":"()V"
stack 1 locals 1
  {
aload_0;
invokespecial   Method java/lang/Object."":"()V";
return;
  }

  static Method testMethod:"()[I"
stack 6 locals 1
  {
getstatic   Field testArray:"[I";
areturn;
  }

} // end Class Test_2

Jdk17/bin/java  -jar asmtools.jar jasm  Test_2.jasm   // create the .class file 
of Test_2
Jdk17/bin/java  Test_1
java.lang.IllegalAccessException: no such method: 
Test_2.testMethod()int[]/invokeStatic
at 
java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:972)
at 
java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1117)
at 
java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:3649)
at 
java.base/java.lang.invoke.MethodHandles$Lookup.findStatic(MethodHandles.java:2588)
at Test_1.(Test_1.java:9)
Caused by: java.lang.VerifyError: Inconsistent stackmap frames at branch target 
15
Exception Details:
  Location:
Test_2.()V @15: iload
  Reason:
Type top (current frame, locals[0]) is not assignable to integer (stack 
map, locals[0])
  Current Frame:
bci: @9
flags: { }
locals: { top, top, top, top, top, top, top, integer }
stack: { integer, integer }
  Stackmap Frame:
bci: @15
flags: { }
locals: { integer, '[B', '[B', '[Ljava/lang/Class;', '[I', '[I', '[I', 
integer, top, top, float, float }
stack: { }
  Bytecode:
000: 10fe 3607 1507 1103 e5a1 0006 0336 0815
010: 0836 08b1
  Stackmap Table:

full_frame(@15,{Integer,Object[#11],Object[#11],Object[#20],Object[#5],Object[#5],Object[#5],Integer,Top,Top,Float,Float},{})

at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at 
java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1085)
at 
java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1114)
... 3 more

Test_2 was intentionally modified to throw VerifyError if initialized.
As you see above,  mh.inovke() was commented out in Test_1.main() but the 
Test_2 was still verified in the test.
So it is impossible to verify Test_2 if it is not initialized, which only means 
Test_2 is initialized during the lookup.findstatic rather than mh.invoke().

Best Regards
Cheng

- Original Message -
> From: "Cheng Jin" 
> To: "core-libs-dev" 
> Sent: Thursday, March 17, 2022 5:42:57 PM
> Subject: When to initialize the method's class for 
> MethodHandles.Lookup.findStatic()?

> Hi there,
> 
> The document of
> INVALID URI REMOVED
> n_java_javase_17_docs_api_java.base_java_lang_invoke_MethodHandles.Loo
> kup.html-23findStatic-28java.lang.Class-2Cjava.lang.String-2Cjava.lang
> .invoke.MethodType-29=DwIFaQ=jf_iaSHvJObTbx-siA1ZOg=X90f3XIRXAH8
> hbNam6bIUlWfF_qUAezL9ue7M7bFuPQ=Xt-10pHYoPWnY6dByKowR4yeLtEs7kZkKUgt
> bxKUGvM=dPAMGMxphLLXT9N4ZdukiNvWyvRPAGkcGCBLTy_sm0c=
> in the Java API is ambiguous in terms of when to initialize the 
> method's class as follows (the same description as in other OpenJDK 
> versions)
> 
> If the returned method handle is invoked, the method's class will be 
> initialized, if it has not already been initialized.
> 
> 
> It occurs to me that the method's class should be initialized when 
> invoking the method handle but OpenJDK actually chooses to do the 
> initialization in
> lookup.findStatic() rather than in mh.

RE: When to initialize the method's class for MethodHandles.Lookup.findStatic()?

2022-03-17 Thread Cheng Jin
Hi David,

1) for the test with mh.invoke() in main(),  the log shows:
[0.262s][info][class,init] Start class verification for: Test_1
[0.262s][info][class,init] End class verification for: Test_1
[0.263s][info][class,init] 282 Initializing 'Test_1' (0x000800c00800)
[0.263s][info][class,init] Start class verification for: Test_2
[0.263s][info][class,init] End class verification for: Test_2
[0.272s][info][class,init] 366 Initializing 'Test_2' (0x000800c00a08) 
<--

2) for the test without  mh.invoke() in main(),  the log shows:
[0.296s][info][class,init] Start class verification for: Test_1
[0.296s][info][class,init] End class verification for: Test_1
[0.297s][info][class,init] 282 Initializing 'Test_1' (0x000800c00800)
[0.297s][info][class,init] Start class verification for: Test_2
[0.297s][info][class,init] End class verification for: Test_2
(Test_2 was verified but didn't get initialized)

The comparison above literally surprised me that the bytecode verification 
happened prior to the class initialization, which means
the class got verified at first even without initialization coz I previously 
thought the initialization should trigger the verification rather than in the 
reversed order.

Could you explain a little more about why it goes in this way?

Best Regards
Cheng


-Original Message-
From: core-libs-dev  On Behalf Of David 
Holmes
Sent: March 17, 2022 7:46 PM
To: Raffaello Giulietti ; 
core-libs-dev@openjdk.java.net
Subject: [EXTERNAL] Re: When to initialize the method's class for 
MethodHandles.Lookup.findStatic()?

Run with -Xlog:class+init=info to see the classes that get initialized and in 
what order.

David

On 18/03/2022 5:53 am, Raffaello Giulietti wrote:
> Hi again,
> 
> here's code that shows that initialization doesn't happen during 
> lookup but only upon invoking the method handle. (I'm on Java 17.)
> 
> As long as the 2nd line in main() is commented, you don't see the 
> message "Test_2 initialized", which shows that the lookup doesn't 
> initialize Test_2.
> When you uncomment the line in main(), the message will appear.
> 
> So, as advertised, it's the invocation of the method handle that can 
> trigger initialization, not the lookup.
> 
> 
> HTH
> Raffaello
> 
> 
> 
> import java.lang.invoke.*;
> 
> public class Test_1 {
> 
>      static MethodHandle mh;
> 
>      static {
>      try {
>      mh = MethodHandles.lookup().findStatic(Test_2.class,
> "testMethod", MethodType.methodType(int.class, int.class));
>      } catch (NoSuchMethodException | IllegalAccessException e) {
>      e.printStackTrace();
>      }
>      }
> 
>      public static void main(String[] args) throws Throwable {
>      System.out.println(mh);
>      // System.out.println(Test_1.mh.invoke(0));
>      }
> 
> }
> 
> 
> 
> 
> public class Test_2 {
> 
>      static {
>      System.out.println("Test_2 initialized");
>      }
> 
>      static int testMethod(int value) { return (value + 1); }
> 
> }
> 
> 
> 
> 
> On 2022-03-17 20:38, Raffaello Giulietti wrote:
>> Hi,
>>
>> as far as I can see, the code should not even compile, as there's a 
>> static field in Test_1 which is initialized with an expression that 
>> throws checked exceptions (findStatic(..)).
>>
>> In addition, it seems to me that there's nothing in your code that 
>> reveals whether Test_2 has been initialized during the lookup. How 
>> can you tell?
>>
>> Finally, the method handle invocation in Test_1 will throw, as you 
>> don't pass any argument to a handle that expects one.
>>
>> Can you perhaps add more details?
>>
>>
>> Greetings
>> Raffaello
>>
>>
>>
>> On 2022-03-17 17:42, Cheng Jin wrote:
>>> Hi there,
>>>
>>> The document of
>>> INVALID URI REMOVED
>>> _en_java_javase_17_docs_api_java.base_java_lang_invoke_MethodHandles
>>> .Lookup.html-23findStatic-28java.lang.Class-2Cjava.lang.String-2Cjav
>>> a.lang.invoke.MethodType-29=DwIDaQ=jf_iaSHvJObTbx-siA1ZOg=X90f
>>> 3XIRXAH8hbNam6bIUlWfF_qUAezL9ue7M7bFuPQ=RvhguidNJ90V-HK-3Ctl-kUZE5
>>> cIfo_nt3_r8VZ0Fcc=tw_ph6oUkS0eCvzITWi9zEkarss5yNeHDrAIfvd3s3g=
>>> in the Java API is ambiguous in terms of when to initialize the 
>>> method's class as follows (the same description as in other OpenJDK
>>> versions)
>>>
>>> If the returned method handle is invoked, the method's class will be 
>>> initialized, if it has not already been initialized.
>>>
>>>
>>> It occurs to me that the method's class should be initialized when 
>>> invoking t

RE: When to initialize the method's class for MethodHandles.Lookup.findStatic()?

2022-03-17 Thread Cheng Jin
Hi Raffaello,

My concern is why the verification happens even without initialization in the 
test without mh.invoke() in the main(), which I don't think is covered or 
explained in the JVM Spec.
Put it in another way, my understanding is, when the class gets loaded, it is 
verified which doesn't necessarily lead to initialization, am I correct?

Best Regards
Cheng

-Original Message-
From: core-libs-dev  On Behalf Of 
Raffaello Giulietti
Sent: March 17, 2022 8:35 PM
To: core-libs-dev@openjdk.java.net
Subject: [EXTERNAL] Re: When to initialize the method's class for 
MethodHandles.Lookup.findStatic()?

Cheng,

initialization is the last thing that happens because it's where user provided 
code gets executed.

This has always been this way, as long as I can remember. See the JVMS for the 
gory details.


Greetings
Raffaello


On 2022-03-18 01:21, Cheng Jin wrote:
> Hi David,
> 
> 1) for the test with mh.invoke() in main(),  the log shows:
> [0.262s][info][class,init] Start class verification for: Test_1
> [0.262s][info][class,init] End class verification for: Test_1
> [0.263s][info][class,init] 282 Initializing 'Test_1' (0x000800c00800)
> [0.263s][info][class,init] Start class verification for: Test_2
> [0.263s][info][class,init] End class verification for: Test_2
> [0.272s][info][class,init] 366 Initializing 'Test_2' (0x000800c00a08) 
> <--
> 
> 2) for the test without  mh.invoke() in main(),  the log shows:
> [0.296s][info][class,init] Start class verification for: Test_1
> [0.296s][info][class,init] End class verification for: Test_1
> [0.297s][info][class,init] 282 Initializing 'Test_1' (0x000800c00800)
> [0.297s][info][class,init] Start class verification for: Test_2
> [0.297s][info][class,init] End class verification for: Test_2
> (Test_2 was verified but didn't get initialized)
> 
> The comparison above literally surprised me that the bytecode verification 
> happened prior to the class initialization, which means
> the class got verified at first even without initialization coz I previously 
> thought the initialization should trigger the verification rather than in the 
> reversed order.
> 
> Could you explain a little more about why it goes in this way?
> 
> Best Regards
> Cheng
> 
> 
> -Original Message-
> From: core-libs-dev  On Behalf Of David 
> Holmes
> Sent: March 17, 2022 7:46 PM
> To: Raffaello Giulietti ; 
> core-libs-dev@openjdk.java.net
> Subject: [EXTERNAL] Re: When to initialize the method's class for 
> MethodHandles.Lookup.findStatic()?
> 
> Run with -Xlog:class+init=info to see the classes that get initialized and in 
> what order.
> 
> David
> 
> On 18/03/2022 5:53 am, Raffaello Giulietti wrote:
>> Hi again,
>>
>> here's code that shows that initialization doesn't happen during
>> lookup but only upon invoking the method handle. (I'm on Java 17.)
>>
>> As long as the 2nd line in main() is commented, you don't see the
>> message "Test_2 initialized", which shows that the lookup doesn't
>> initialize Test_2.
>> When you uncomment the line in main(), the message will appear.
>>
>> So, as advertised, it's the invocation of the method handle that can
>> trigger initialization, not the lookup.
>>
>>
>> HTH
>> Raffaello
>>
>> 
>>
>> import java.lang.invoke.*;
>>
>> public class Test_1 {
>>
>>       static MethodHandle mh;
>>
>>       static {
>>       try {
>>       mh = MethodHandles.lookup().findStatic(Test_2.class,
>> "testMethod", MethodType.methodType(int.class, int.class));
>>       } catch (NoSuchMethodException | IllegalAccessException e) {
>>       e.printStackTrace();
>>       }
>>       }
>>
>>       public static void main(String[] args) throws Throwable {
>>       System.out.println(mh);
>>       // System.out.println(Test_1.mh.invoke(0));
>>       }
>>
>> }
>>
>>
>>
>>
>> public class Test_2 {
>>
>>       static {
>>       System.out.println("Test_2 initialized");
>>       }
>>
>>       static int testMethod(int value) { return (value + 1); }
>>
>> }
>>
>>
>>
>>
>> On 2022-03-17 20:38, Raffaello Giulietti wrote:
>>> Hi,
>>>
>>> as far as I can see, the code should not even compile, as there's a
>>> static field in Test_1 which is initialized with an expression that
>>> throws checked exceptions (findStatic(..)).
>>>
>>> In addition, it seems to me that there's nothing in your code that
>>> reveals whether Test_2 has 

Incorrect return value for Java_jdk_internal_loader_NativeLibraries_load() in java.base/share/native/libjava/NativeLibraries.c

2022-02-23 Thread Cheng Jin
Hi there,

The return value from Java_jdk_internal_loader_NativeLibraries_load() at 
https://github.com/openjdk/jdk/blob/master/src/java.base/share/native/libjava/NativeLibraries.c
seems incorrect according to the code logic in there.

Looking at the calling path from  loadLibrary() to load() at 
src/java.base/share/classes/jdk/internal/loader/NativeLibraries.java as follows:

public NativeLibrary loadLibrary(Class fromClass, String name) {
...
NativeLibrary lib = findFromPaths(LibraryPaths.SYS_PATHS, fromClass, 
name); <--
if (lib == null && searchJavaLibraryPath) {
lib = findFromPaths(LibraryPaths.USER_PATHS, fromClass, name); <
}
return lib;
}

  private NativeLibrary findFromPaths(String[] paths, Class fromClass, 
String name) {
for (String path : paths) {  < keep searching the 
library paths till the library is located at the correct lib path
File libfile = new File(path, System.mapLibraryName(name));
NativeLibrary nl = loadLibrary(fromClass, libfile);  ?
if (nl != null) {
return nl; <
}
libfile = ClassLoaderHelper.mapAlternativeName(libfile);
if (libfile != null) {
nl = loadLibrary(fromClass, libfile);
if (nl != null) {
return nl;
}
}
}
return null;
}

public NativeLibrary loadLibrary(Class fromClass, File file) {
   // Check to see if we're attempting to access a static library
String name = findBuiltinLib(file.getName());
boolean isBuiltin = (name != null);
...
return loadLibrary(fromClass, name, isBuiltin);  <
}

   private NativeLibrary loadLibrary(Class fromClass, String name, boolean 
isBuiltin) {
   ...
NativeLibraryImpl lib = new NativeLibraryImpl(fromClass, name, 
isBuiltin, isJNI);

   // load the native library
NativeLibraryContext.push(lib);
try {
if (!lib.open()) {  <- call load()
return null;// fail to open the native library
}
 ...
   // register the loaded native library
loadedLibraryNames.add(name);
libraries.put(name, lib);
return lib;  <--- return an invalid lib as lib.open() 
returns true
} finally {
releaseNativeLibraryLock(name);
}
  ...
  }

/*
 * Loads the named native library
 */
boolean open() {
...
return load(this, name, isBuiltin, isJNI, loadLibraryOnlyIfPresent);
}

private static native boolean load(NativeLibraryImpl impl, String name, 
boolean isBuiltin, boolean isJNI, boolean throwExceptionIfFail);

and then native code in java.base/share/native/libjava/NativeLibraries.c

Java_jdk_internal_loader_NativeLibraries_load
  (JNIEnv *env, jobject this, jobject lib, jstring name,
   jboolean isBuiltin, jboolean isJNI, jboolean throwExceptionIfFail)
{
const char *cname;
jint jniVersion;
jthrowable cause;
void * handle;
jboolean loaded = JNI_FALSE;
   ...
handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname, 
throwExceptionIfFail);
if (isJNI) {
   ...
}
(*env)->SetLongField(env, lib, handleID, ptr_to_jlong(handle));
loaded = JNI_TRUE;  <- always return true when isJNI is false and a 
null handle

done:
JNU_ReleaseStringPlatformChars(env, name, cname);
return loaded;
}

Assuming there are multiple library paths existing in the jdk/lib which are 
added to sun.boot.library.path and java.library.path
and the expected library (libnative.so) is only placed in jdk/lib. e.g.
lib/libA
lib/libB
lib/libC
lib/libnative.so

when the code in findFromPaths() searches the library paths set in 
sun.boot.library.path and java.library.path starting from lib/LibA,
it will end up with an invalid value if load() returns true in the case of a 
false isJNI and a null handle returned from JVM_LoadLibrary()
as the library doesn't exist in lib/libA passed to JVM_LoadLibrary().

To ensure findFromPaths() keeps searching the remaining lib paths,  the simple 
fix should look like:
Java_jdk_internal_loader_NativeLibraries_load( ...)
{
...
(*env)->SetLongField(env, lib, handleID, ptr_to_jlong(handle));
if (handle) {  <- return true only for a non-null 
handle
loaded = JNI_TRUE;
}
...
}

Please help check the code around there to see whether the fix is reasonable to 
avoid the unexpected situation as explained above (the problem was spotted 
since JDK17)

Best Regards
Cheng Jin


When to initialize the method's class for MethodHandles.Lookup.findStatic()?

2022-03-17 Thread Cheng Jin
Hi there,

The document of  
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/MethodHandles.Lookup.html#findStatic(java.lang.Class,java.lang.String,java.lang.invoke.MethodType)
 in the Java API is ambiguous in terms of when to initialize the method's class 
as follows (the same description as in other OpenJDK versions)

If the returned method handle is invoked, the method's class will be 
initialized, if it has not already been initialized.


It occurs to me that the method's class should be initialized when invoking the 
method handle but OpenJDK actually chooses to do the initialization in 
lookup.findStatic() rather than in mh.invoke()
e.g.
import java.lang.invoke.*;

public class Test_1 {
static MethodHandle mh = MethodHandles.lookup().findStatic(Test_2.class, 
"testMethod", MethodType.methodType(int.class, int.class)); <--- 
Test_2.class gets initialized and verified.

public static void main(String[] args) throws Throwable {
Test_1.mh.invoke();
}
}

public class Test_2 {
static int testMethod(int value) { return (value + 1); }
}

So there should be more clear explanation what is the correct or expected 
behaviour at this point and why OpenJDK doesn't comply with the document to 
delay the initialization of the method's class to mh.invoke().

Best Regards
Cheng Jin