Re: RFR: JDK-8242888: Convert dynamic proxy to hidden classes

2022-04-19 Thread Johannes Kuhn
On Sun, 17 Apr 2022 16:17:30 GMT, liach  wrote:

> Convert dynamic proxies to hidden classes. Modifies the serialization of 
> proxies (requires change in "Java Object Serialization Specification"). Makes 
> the proxies hidden in stack traces. Removes duplicate logic in proxy building.
> 
> The main compatibility changes and their rationales are:
> 1. Modification to the serialization specification: In the "An instance of 
> the class is allocated... The contents restored appropriately" section, I 
> propose explicitly state that handling of proxies are unspecified as to allow 
> implementation freedom, though I've seen deliberate attempts for proxies to 
> implement interfaces with `readResolve` in order to control their 
> serialization behavior.
>- This is for the existing generated constructor accessor is 
> bytecode-based, which cannot refer to hidden classes.
>- An alternative is to preserve the behavior, where the serialization 
> constructor calls `invokespecial` on the closest serializable superclass' 
> no-arg constructor, like in #1830 by @DasBrain.
>- My rationale against preservation is such super calls are unsafe and 
> should be discouraged in the long term. Calling the existing constructor with 
> a dummy argument, as in my implementation, would be more safe.
> 2. The disappearance of proxies in stack traces.
>- Same behavior exists in lambda expressions: For instance, in 
> `((Runnable) () -> { throw new Error(); }).run();`, the `run` method, 
> implemented by the lambda, will not appear in the stack trace, and isn't too 
> problematic.
> 
> A summary of the rest of the changes:
> 1. Merged the two passes of determining module and package of the proxy into 
> one. This reduced a lot of code and allowed anchor class (for hidden class 
> creation) selection be done together as well.
> 2. Exposed internal API for obtaining a full-privileged lookup to the rest of 
> `java.base`. This API is intended for implementation of legacy (pre 
> `MethodHandles.Lookup`) caller sensitive public APIs so they don't need more 
> complex tricks to obtain proper permissions as lookups.
> 3. Implements [8229959](https://bugs.openjdk.java.net/browse/JDK-8229959): 
> passes methods computed by proxy generator as class data to the hidden proxy 
> class to reduce generated proxy class size and improve performance.
> 
> In addition, since this change is somewhat large, should we keep the old 
> proxy generator as well and have it toggled through a command-line flag (like 
> the old v49 proxy generator or the old reflection implementation)?
> 
> Please feel free to comment or review. This change definitely requires a CSR, 
> but I have yet to determine what specifications should be changed.

About deserializing Proxies, this is currently done in 3 steps:

1. Finding the class
2. Allocating a new instance and invoke the constructor of the **first 
non-serializable superclass**
3. Setting the fields of the instance

Only step 2 is problematic here:

1. For a proxy, the class is serialized using a TC_PROXYCLASSDESC. when 
deserialized it invokes `Proxy.getProxyClass` 
(https://github.com/openjdk/jdk/blob/13fb1eed52f1a9152242119969a9d4a0c0627513/src/java.base/share/classes/java/io/ObjectInputStream.java#L891).
  
For this step, it doesn't matter if `Proxy.getProxyClass` returns a normal 
class or a hidden class.
2. Allocating and calling the constructor:  
 This part is currently implemented by spinning a class. The generated 
bytecode looks more or less like this:

anew ProxyClass
invokespecial Object.()

The big lie here is that methods and constructors are different - but 
constructors are just methods, and the verifier makes sure that a constructor 
is called only once, exactly once, and that uninitialized instances don't 
escape.

This doesn't work for hidden classes - as the hidden class can not be named 
in an other class.  
But MethodHandles can do this. Here is one of my old prototypes, based on a 
prototype for implementing reflection using MethodHandles from Mandy Chung: 
https://github.com/dasbrain/jdk/compare/ae45c5de7fc635df4dc86b764405158c245d2765...fbb0a63436f696a85e7039c0e109c379dfa1edce

3. Setting the fields uses deep reflection.   
But the hidden class themself doesn't have any fields - just it's 
superclass `java.lang.reflect.Proxy.h`.  
This is not a problem if the class can be instantiated at all (see step 2).

-

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


Re: RFR: 8283237: CallSite should be a sealed class

2022-03-16 Thread Johannes Kuhn
On Wed, 16 Mar 2022 13:09:30 GMT, liach  wrote:

> Change `CallSite` to a sealed class, as `CallSite` is an abstract class which 
> does not allow direct subclassing by users per its documentation. Since I 
> don't have a JBS account, I posted the content for the CSR in a GitHub Gist 
> at https://gist.github.com/150d5aa7f8b13a4deddf95969ad39d73 and wish someone 
> can submit a CSR for me.

Marked as reviewed by jkuhn (Author).

-

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


Re: RFR: 8280377: MethodHandleProxies does not correctly invoke default methods with varags [v4]

2022-01-25 Thread Johannes Kuhn
On Tue, 25 Jan 2022 21:35:27 GMT, Mandy Chung  wrote:

>> The MethodHandle of a default method should be made as a fixed arity method 
>> handle because it is invoked via Proxy's invocation handle with a non-vararg 
>> array of arguments.  On the other hand, the 
>> `InvocationHandle::invokeDefault` method  was added in Java 16 to invoke a 
>> default method of a proxy instance.  This patch simply converts the 
>> implementation to call `InvocationHandle::invokeDefault` instead.
>
> Mandy Chung has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   add comment

My question was for when a library wants to implement something similar to 
`MethodHandleProxies.asInterfaceInstace`, and for example supports Interfaces 
with more than a single abstract method.  
Currently, such a library would also have to call 
`ReflectAccess.invokeDefault`, as the interface may not be accessible by the 
`InvocationHandler` (as it could be the case with 
`MethodHandleProxies.asInterfaceInstace`

But this might be a discussion for an other time.  
Patch looks good.

-

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


Re: RFR: 8280377: MethodHandleProxies does not correctly invoke default methods with varags [v2]

2022-01-24 Thread Johannes Kuhn
On Mon, 24 Jan 2022 23:03:49 GMT, Mandy Chung  wrote:

>> The MethodHandle of a default method should be made as a fixed arity method 
>> handle because it is invoked via Proxy's invocation handle with a non-vararg 
>> array of arguments.  On the other hand, the 
>> `InvocationHandle::invokeDefault` method  was added in Java 16 to invoke a 
>> default method of a proxy instance.  This patch simply converts the 
>> implementation to call `InvocationHandle::invokeDefault` instead.
>
> Mandy Chung has updated the pull request incrementally with three additional 
> commits since the last revision:
> 
>  - revert MethodHandlesProxiesTest change
>  - Add new regression test
>  - Should not perform access check on the interface as specified

Changes requested by jkuhn (Author).

src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java line 206:

> 204: if (isDefaultMethod(method)) {
> 205: // no additional access check is performed
> 206: return JLRA.invokeDefault(proxy, method, null, 
> args);

Isn't the argument order `..., args, caller`?

src/java.base/share/classes/java/lang/reflect/ReflectAccess.java line 134:

> 132: throws Throwable {
> 133: return Proxy.invokeDefault(proxy, method, args, caller);
> 134: }

What about other, non-jdk code that wishes to implement a similar thing - make 
a proxy for an arbitrary interface and handle default methods by invoking them?

-

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


Re: RFR: 8280377: MethodHandleProxies does not correctly invoke default methods with varags

2022-01-22 Thread Johannes Kuhn
On Fri, 21 Jan 2022 22:49:38 GMT, Mandy Chung  wrote:

> The MethodHandle of a default method should be made as a fixed arity method 
> handle because it is invoked via Proxy's invocation handle with a non-vararg 
> array of arguments.  On the other hand, the `InvocationHandle::invokeDefault` 
> method  was added in Java 16 to invoke a default method of a proxy instance.  
> This patch simply converts the implementation to call 
> `InvocationHandle::invokeDefault` instead.

When testing this patch from a named module and not-exported package, I get the 
following exception:


Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at jdk.proxy1/com.sun.proxy.jdk.proxy1.$Proxy0.toString(Unknown Source)
at test.openjdk/test.openjdk.ProxyTest.main(ProxyTest.java:22)
Caused by: java.lang.IllegalAccessException: class 
java.lang.invoke.MethodHandleProxies$1 (in module java.base) cannot access 
interface test.openjdk.ProxyTest$Test (in module test.openjdk) because module 
test.openjdk does not export test.openjdk to module java.base
at 
java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:394)
at 
java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at 
java.base/java.lang.reflect.InvocationHandler.invokeDefault(InvocationHandler.java:278)
at 
java.base/java.lang.invoke.MethodHandleProxies$1.invoke(MethodHandleProxies.java:202)
... 2 more


[My test 
code](https://gist.github.com/DasBrain/60dbc1c9075b15635d9c87e8295f1c1a).  
Running without the patch results in the wrong output for default varargs 
methods, so this is a regression.

-

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


Re: Looking for a starter task. Maybe JDK-8253396 (Please add `not()` method to `java.util.function.BiPredicate`)?

2021-03-23 Thread Johannes Kuhn

Hi and welcome.

I would not consider JDK-8253396 (Please add `not()` method to 
`java.util.function.BiPredicate`) a good starter bug.


Generally, any bug that tries to add new APIs are hard, and require a 
lot of time and effort.


While the implementation of java.util.function.BiPredicate.not() is 
probably trivial, doing this task requires much more work:


* There should be some discussion if this feature is needed - this 
mailing list is the right place for that.
* The method needs a well written specification, in form of a javadoc 
comment.

* Tests need to be written to ensure conformance with the specification.

This is my current understanding on how to add new APIs. If I am wrong, 
please correct me.


I would not recommend adding a new API as a starter bug. From my limited 
experience, great starter bugs are bugs where the wrong exception is 
thrown - they are easy to fix, but still require you to write additional 
tests.


But if you find a sponsor who helps you implement JDK-8253396, then go 
for it.


- Johannes


On 20-Mar-21 7:31, Suren Nihalani wrote:

Hi,

I am new openjdk (I've been using java for 7 years but I am new to
contributing to openjdk!). I was looking for interesting starter tasks to
help out with. JDK-8253396 looked like an easy to implement candidate. I am
open to other suggestions too (feel free to little r as well)!

The contribution guide suggested I socialize my change before I code it up.
Seems like the implementation would be straightforward and similar to
Predicate.java. Are folks okay with this change?

Thanks for looking into this!



Re: RFR: 8263508: Remove dead code in MethodHandleImpl

2021-03-12 Thread Johannes Kuhn
On Fri, 12 Mar 2021 13:27:39 GMT, Claes Redestad  wrote:

> Remove unused methods.

LGTM

-

Marked as reviewed by jkuhn (Author).

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


Re: JDK-8262003: Class.arrayType should not throw IllegalArgumentException

2021-02-25 Thread Johannes Kuhn

Thanks Mandy.

Will amend the CSR to cover TypeDescriptor.OfField::arrayType as well, 
and create a patch.


Where should I put the tests?
Didn't find any tests that exercise Class::arrayType in test/jdk/java/lang/.
Any wishes for tests that I should add w.r.t. Class::arrayType?

- Johannes

On 24-Feb-21 20:54, Mandy Chung wrote:

Hi Johannes,

Changing Class::arrayType to throw ISA makes sense to me.   I think 
`TypeDescriptor.ofField::arrayType` spec should also be updated to throw 
ISA to follow what JVM checks for array dimension because it's a static 
constraint check [1] (rather than a resolution error) for `anewarray` 
instruction to create an array no more than 255 dimensions.


The CSR looks okay.  I agree that the compatibility risk is low.

I'd like to review PR along with CSR together.

Mandy
[1] 
https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-4.html#jvms-4.9.1


On 2/23/21 6:38 AM, Johannes Kuhn wrote:
I want to learn about writing a CSR, and need a sponsor teaching me 
the ropes.




Bug: https://bugs.openjdk.java.net/browse/JDK-8262003

Currently, Class.arrayType() will throw an IllegalArgumentException if 
the maximum number of dimensions will be exceeded.


Throwing an IllegalArgumentException from a method that doesn't take 
an argument is, at least, strange.


Therefore I would like to update the specification to allow this 
method to throw an IllegalStateException, similar to what 
ClassDesc.arrayType() does.




The current plan is:

* Create a CSR detailing the spec changes: 
https://bugs.openjdk.java.net/browse/JDK-8262211
* Surround the code with a try-catch block. Checking for the error 
case is hard, and somewhat rare, so I think this is appropriate.
* Copy the @throws javadoc line from ClassDesc.arrayType to 
Class.arrayType


But there are a few questions I would love to get the answer on:

* Both Class.arrayType() and ClassDesc.arrayType() are specified by 
TypeDescriptor.OfField. Should the specification of 
TypeDescriptor.OfField.arrayType() changed as well?
* Is the draft of my CSR fine? Should I add some details, or omit 
things? Rephrase things?


In advance, thanks for any support and feedback on this.

- Johannes




JDK-8262003: Class.arrayType should not throw IllegalArgumentException

2021-02-23 Thread Johannes Kuhn
I want to learn about writing a CSR, and need a sponsor teaching me the 
ropes.




Bug: https://bugs.openjdk.java.net/browse/JDK-8262003

Currently, Class.arrayType() will throw an IllegalArgumentException if 
the maximum number of dimensions will be exceeded.


Throwing an IllegalArgumentException from a method that doesn't take an 
argument is, at least, strange.


Therefore I would like to update the specification to allow this method 
to throw an IllegalStateException, similar to what ClassDesc.arrayType() 
does.




The current plan is:

* Create a CSR detailing the spec changes: 
https://bugs.openjdk.java.net/browse/JDK-8262211
* Surround the code with a try-catch block. Checking for the error case 
is hard, and somewhat rare, so I think this is appropriate.

* Copy the @throws javadoc line from ClassDesc.arrayType to Class.arrayType

But there are a few questions I would love to get the answer on:

* Both Class.arrayType() and ClassDesc.arrayType() are specified by 
TypeDescriptor.OfField. Should the specification of 
TypeDescriptor.OfField.arrayType() changed as well?
* Is the draft of my CSR fine? Should I add some details, or omit 
things? Rephrase things?


In advance, thanks for any support and feedback on this.

- Johannes


Re: JDK-6824466 java.lang.reflect.Method should use java.lang.invoke.MethodHandle

2021-02-08 Thread Johannes Kuhn

I now implemented a prototype for JDK-6824466: [1]

The goal I set here was to remove the old AccessorGenerator.

The good news:

- It works - all tier1 tests pass, except one that requires the old 
implementation.

- A lot of code has been removed. And even more could be removed.

The bad news:

- I hit a performance regression [2].

The JMH tests were written by Peter Levart [3].
As much as I don't like the old AccessorGenerator, I have to say that it 
is very optimized.


If you have any ideas on how the performance could be improved, or how I 
could find that out where the performance drops, let me know.


- Johannes

PS.: I played around with adding some @Stable and @ForceInline 
annotations, and got a big performance improvement for the const cases 
(~9 ns/op). But that came with other performance regressions for the 
non-const cases.



[1]: https://github.com/openjdk/jdk/pull/2457
[2]: 
https://gist.github.com/DasBrain/09b37510955b14f0ad82313df8d8de37#gistcomment-3623292
[3]: 
http://cr.openjdk.java.net/~plevart/jdk-dev/6824466_MHReflectionAccessors/


Re: RFR: 8261254: Initialize charset mapping data lazily

2021-02-08 Thread Johannes Kuhn
On Sun, 7 Feb 2021 19:08:18 GMT, Claes Redestad  wrote:

> This patch refactor JDK internal charsets to initialize charset mapping data 
> lazily when needed via holder classes. This means both a startup improvement 
> in some cases, and possible throughput improvements for all DoubleByte-based 
> Charsets.
> 
> Testing: tier1-3

Looks good to me.

src/java.base/share/classes/java/lang/ModuleLayer.java line 936:

> 934: for (Module m : nameToModule.values()) {
> 935: servicesCatalog.register(m);
> 936: }

Seems to be unrelated, but it's not a bad change.

-

Marked as reviewed by jkuhn (Author).

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


Re: RFR: 8013527: calling MethodHandles.lookup on itself leads to errors [v2]

2021-02-03 Thread Johannes Kuhn
On Wed, 3 Feb 2021 18:40:15 GMT, Mandy Chung  wrote:

>> JDK-8013527: calling MethodHandles.lookup on itself leads to errors
>> JDK-8257874: MethodHandle injected invoker doesn't have necessary private 
>> access
>> 
>> Johannes Kuhn is also a contributor to this patch.
>> 
>> A caller-sensitive method can behave differently depending on the identity
>> of its immediate caller.  If a method handle for a caller-sensitive method is
>> requested, this resulting method handle behaves as if it were called from an
>> instruction contained in the lookup class.  The current implementation 
>> injects
>> a trampoline class (aka the invoker class) which is the caller class invoking
>> such caller-sensitive method handle.  It works in all CSMs except 
>> `MethodHandles::lookup`
>> because the caller-sensitive behavior depends on the module of the caller 
>> class,
>> the class loader of the caller class, the accessibility of the caller class, 
>> or
>> the protection domain of the caller class.  The invoker class is a hidden 
>> class
>> defined in the same runtime package with the same protection domain as the
>> lookup class, which is why the current implementation works for all CSMs 
>> except
>> `MethodHandles::lookup` which uses the caller class as the lookup class.
>> 
>> Two issues with current implementation:
>> 1.  The invoker class only has the package access as the lookup class.  It 
>> cannot
>> access private members of the lookup class and its nest members.
>> 
>> The fix is to make the invoker class as a nestmate of the lookup class.
>> 
>> 2.  `MethodHandles::lookup` if invoked via a method handle produces a 
>> `Lookup`
>> object of an injected invoker class which is a bug.
>> 
>> There are two alternatives:
>> - define the invoker class with the lookup class as the class data such that
>>   `MethodHandles::lookup` will get the caller class from the class data if
>>   it's the injected invoker
>> - Johannes' proposal [1]: detect if an alternate implementation with an 
>> additional
>>   trailing caller class parameter is present, use the alternate 
>> implementation
>>   and bind the method handle with the lookup class as the caller class 
>> argument.
>> 
>> There has been several discussions on the improvement to support caller 
>> sensitive
>> methods for example the calling sequences and security implication.   I have
>> looked at how each CSM uses the caller class.  The second approach (i.e. 
>> defining an alternate implementation for a caller-sensitive method taking
>> an additional caller class parameter) does not work for non-static non-final
>> caller-sensitive method.  In addition, it is not ideal to pollute the source
>> code to provide an alternatve implementation for all 120+ caller-sensitive 
>> methods
>> whereas the injected invoker works for all except `MethodHandles::lookup`.
>> 
>> I propose to use both approaches.   We can add an alternative implementation 
>> for
>> a caller-sensitive method when desirable such as `MethodHandles::lookup` in
>> this PR.  For the injected invoker case, one could extract the original 
>> lookup
>> class from class data if needed.
>> 
>> test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSM.java ensures that
>> no new non-static non-final caller-sensitive method will be added to the JDK.
>> I extend this test to catch that non-static non-final caller-sensitive method
>> cannot have the alternate implementation taking the additional caller class
>> parameter.
>> 
>> This fix for JDK-8013527 is needed by the prototype for JDK-6824466 I'm 
>> working on.
>> 
>> [1] 
>> https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-January/073184.html
>
> Mandy Chung has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Support MethodHandles::lookup called via Method::invoke via MethodHandle

Looks good.

-

Marked as reviewed by dasbr...@github.com (no known OpenJDK username).

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


Re: RFR: 8013527: calling MethodHandles.lookup on itself leads to errors [v2]

2021-02-03 Thread Johannes Kuhn
On Wed, 3 Feb 2021 18:34:55 GMT, Mandy Chung  wrote:

>> You are right, got it confused with the future use.
>> 
>> With this fix, MethodHandle -> Method.invoke -> MethodHandles.lookup() will 
>> still return a lookup on the injected invoker.  
>> I somehow missed that this is not part of the fix, but for the future use.
>
> `MethodHandle -> Method.invoke -> MethodHandles.lookup() ` is a corner case 
> that can be fixed easily using the class data approach.  See the new commit.

The security issue I mentioned was in an other branch, method-invoke.  

I used commit 
https://github.com/mlchung/jdk/commit/4a3c914f1b46cf84b42f6b6bc19d421955faac3f 
(i.e. before strengthening the injected invoker checks) to test the [my 
exploit](https://gist.github.com/DasBrain/4dda6cc3a13e1636afe17e6a02ec3d12). 
(Yes, full sandbox escape.)

I hope the same is not possible with the nestmate requirement.  

PS.: Hidden Class -> MethodHandle -> Method.invoke -> MethodHandles might break 
due to mangling of the hidden class name for the injected invoker. Will write a 
test.

-

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


Re: RFR: 8013527: calling MethodHandles.lookup on itself leads to errors

2021-02-03 Thread Johannes Kuhn
On Wed, 3 Feb 2021 17:25:04 GMT, Mandy Chung  wrote:

>> Only `Lookup` with the original access can access `MethodHandles.classData`. 
>>   A hidden class `HC$$InjectedInvoker/0x1234` can access private members of 
>> another class `C` in the same nest but not `C`'s class data.
>> 
>> I don't follow which previous commit you refer to more dangerous.  Please 
>> elaborate.   I don't see any security concern with class data.
>
> Last night, I had a second thought that the fix for these two JBS issues does 
> not need the class data.  It's more for a future use.  I plan to revise it 
> and drop class data in this fix anyway.

You are right, got it confused with the future use.

With this fix, MethodHandle -> Method.invoke -> MethodHandles.lookup() will 
still return a lookup on the injected invoker.  
I somehow missed that this is not part of the fix, but for the future use.

-

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


Re: RFR: 8013527: calling MethodHandles.lookup on itself leads to errors

2021-02-03 Thread Johannes Kuhn
On Wed, 3 Feb 2021 01:50:36 GMT, Mandy Chung  wrote:

> JDK-8013527: calling MethodHandles.lookup on itself leads to errors
> JDK-8257874: MethodHandle injected invoker doesn't have necessary private 
> access
> 
> Johannes Kuhn is also a contributor to this patch.
> 
> A caller-sensitive method can behave differently depending on the identity
> of its immediate caller.  If a method handle for a caller-sensitive method is
> requested, this resulting method handle behaves as if it were called from an
> instruction contained in the lookup class.  The current implementation injects
> a trampoline class (aka the invoker class) which is the caller class invoking
> such caller-sensitive method handle.  It works in all CSMs except 
> `MethodHandles::lookup`
> because the caller-sensitive behavior depends on the module of the caller 
> class,
> the class loader of the caller class, the accessibility of the caller class, 
> or
> the protection domain of the caller class.  The invoker class is a hidden 
> class
> defined in the same runtime package with the same protection domain as the
> lookup class, which is why the current implementation works for all CSMs 
> except
> `MethodHandles::lookup` which uses the caller class as the lookup class.
> 
> Two issues with current implementation:
> 1.  The invoker class only has the package access as the lookup class.  It 
> cannot
> access private members of the lookup class and its nest members.
> 
> The fix is to make the invoker class as a nestmate of the lookup class.
> 
> 2.  `MethodHandles::lookup` if invoked via a method handle produces a `Lookup`
> object of an injected invoker class which is a bug.
> 
> There are two alternatives:
> - define the invoker class with the lookup class as the class data such that
>   `MethodHandles::lookup` will get the caller class from the class data if
>   it's the injected invoker
> - Johannes' proposal [1]: detect if an alternate implementation with an 
> additional
>   trailing caller class parameter is present, use the alternate implementation
>   and bind the method handle with the lookup class as the caller class 
> argument.
> 
> There has been several discussions on the improvement to support caller 
> sensitive
> methods for example the calling sequences and security implication.   I have
> looked at how each CSM uses the caller class.  The second approach (i.e. 
> defining an alternate implementation for a caller-sensitive method taking
> an additional caller class parameter) does not work for non-static non-final
> caller-sensitive method.  In addition, it is not ideal to pollute the source
> code to provide an alternatve implementation for all 120+ caller-sensitive 
> methods
> whereas the injected invoker works for all except `MethodHandles::lookup`.
> 
> I propose to use both approaches.   We can add an alternative implementation 
> for
> a caller-sensitive method when desirable such as `MethodHandles::lookup` in
> this PR.  For the injected invoker case, one could extract the original lookup
> class from class data if needed.
> 
> test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSM.java ensures that
> no new non-static non-final caller-sensitive method will be added to the JDK.
> I extend this test to catch that non-static non-final caller-sensitive method
> cannot have the alternate implementation taking the additional caller class
> parameter.
> 
> This fix for JDK-8013527 is needed by the prototype for JDK-6824466 I'm 
> working on.
> 
> [1] 
> https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-January/073184.html

Thanks Mandy.

Looks good, except the possibility for an attacker to teleport within the same 
nest.

src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java line 1205:

> 1203: Class invokerClass = new Lookup(targetClass)
> 1204: .makeHiddenClassDefiner(name, 
> INJECTED_INVOKER_TEMPLATE, Set.of(NESTMATE))
> 1205: .defineClass(true, targetClass);

Using the target class directly could lead to some unintended problems.

An attacker can define it's own hidden class as nestmate and with a name ending 
in `$$InjectedInvoker`.  
This allows the attacker to "teleport" into a nestmate with full privileges.  
An attacker could then access `MethodHandles.classData`.

Suggested remedy: Create a holder that is only visible to `java.lang.invoke`:

/* package-private */ static class OriginalCallerHolder {
final Class originalCaller;
OriginalCallerHolder(Class originalCaller) {
this.originalCaller = originalCaller;
}
}

As this type is only visible inside `java.lang.invoke`, it can't be created 
without hacking into `java.lang.invoke`, at which point all bets are

Re: JDK-6824466 java.lang.reflect.Method should use java.lang.invoke.MethodHandle

2021-02-02 Thread Johannes Kuhn

Thanks Alan.

For using MethodHandles and @CS methods: As far as I remember, 
MethodHandle is also skipped on a stack walk for security. In my 
prototype (where I did always use MethodHandles for Method.invoke) 
MethodHandles.class.findStatic("lookup").invoke(null) did return a 
Lookup with the right lookup class.


So, MethodHandles as implementation works - if all classes on the stack 
extend MethodAccessorImpl or MethodHandle.


I did a prototype in the past to use an overload for @CS methods [1]
While C2 could link to the overload directly, this is not needed in my 
prototype.


The roadblock I hit was that Method.invoke is itself @CS, so either the 
Method.invoke overload will have to inject a frame for the caller or all 
@CS methods need to have their overload. (And the overload for 
Method.invoke needs it's own intrinsic, so it's skipped during security 
stack walk.)


The other problem with regard to @CS is Thread.getContextClassLoader().
This method can be virtually called. But a private overload would bypass 
the any override.


Currently, java.lang.invoke will bind the caller if the called method is 
named "getContextClassLoader" and the method is in an interface.


Things get interesting if you consider this interface:

interface GetCCLObject {Object getContextClassLoader();}

javac will now add a bridge method if you extend Thread and implement 
this interface - which calls the @CS method. And that class is now the 
caller.


Not exactly sure what my conclusion is, but I tend to "if you implement 
such an interface, you are out of luck".

(That's the point my head starts to hurt.)

In the end - Loom has an other implementation of JDK-6824466. Makes 4.
Interesting is that they all have been born out of different 
requirements - so it seems indeed to be a good idea.


In my prototype I did fell into the trap that I tried too much at once.
And @CS is a really complex topic that might be attractive to somehow 
squeeze into JDK-6824466. But I'm not convinced that this is a good idea.


- Johannes


[1]: 
https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-January/073184.html


On 02-Feb-21 11:07, Alan Bateman wrote:

On 01/02/2021 15:19, Johannes Kuhn wrote:

:

Thanks Rémi.

The problem here is that (according to Peter Levart tests), the cold 
use of a MHMethodAccessor is 11x as expensive as using the native 
accessor.


In some way, it sill makes sense to keep the native accessor around, 
at least during startup. On the other hand, I heard that there have 
been some improvements on the AppCDS w.r.t MethodHandles, but I'm out 
of the loop there.


An other problem with completely replacing the native accessors is 
some bootstrap problem - if certain flags are set (some of them are 
used to build the CDS), then the java.lang.invoke infrastructure tries 
to write stuff to System.out. But to initialize System.out, the 
charset has to be constructed, which relies on reflection.


I can see some potential in improving the initialization of the 
standard charset, but it's out of the scope here.


Apropos scope: I try to narrow the scope down to "replace 
MethodAccessorGenerator with accessors that delegate to MethodHandles".
Once this is done, then additional improvements can be made - 
including some that take loom into account. Or adding some 
@Stable/@ForceInline stuff so the JIT can better optimize reflective 
calls.


But currently (didn't look into the loom source) there are only two 
strategies: Native accessor (bad for loom) or generated (bytecode 
spinning, doesn't work with hidden classes). So, with loom and hidden 
classes you get the worst of both worlds. MethodHandles solve that.
As things stands, virtual threads don't call through the VM because of 
the potential for blocking with a native trampoline frame on the stack. 
The bytecode generator is still used for @CS methods but otherwise it 
uses method handles. Hidden classes should be okay although we don't 
have tests for that yet. In any case, this will all be replaced once 
Mandy's work is further along. Core reflection usages during initPhase2 
can be dealt it by deferral until the module system is fully initialized 
(as Mandy suggests) as using invoke count would be too fragile. For @CS 
methods you will see linked issues where the suggestion to link to an 
overloaded method that takes the caller class has been suggested. I also 
suspect there will be some C2 work needed.


-Alan


Re: JDK-6824466 java.lang.reflect.Method should use java.lang.invoke.MethodHandle

2021-02-01 Thread Johannes Kuhn

Thanks Mandy.

Yes, the 3 prototypes I mentioned were yours, Peter Levart's, and my own.
(My prototype is at 
https://github.com/DasBrain/jdk/tree/reflection-MHaccessors - I hit an 
boostrap problem, build a workaround that I don't really like, so I 
stopped working on that.)


I agree on your goals, they are the same as mine.

For the constructor story, well, that is a prerequisite for the hidden 
proxy classes. I'll take an other look at your implementation, and maybe 
open a pull request against your repo.


Current approach is to keep the scope small - just replacing the old 
generated accessors with method handle based ones.


Even this "small" change is IMHO worthwhile:

* Getting rid of the old MethodAccessorGenerator (I don't want to 
maintain it, and if I had to, then moving to ASM would be a step forward)
* Better performance on calling methods from hidden classes. (Loom 
doesn't like native frames on the stack)
* Prerequisite for further enchantments, such as hidden proxy classes, 
alternatives for reflective @CS and possible performance improvements 
using @Stable/@ForceInline.


It's just - it's an old bug, and other people already did try some stuff 
on it. So I try to learn from their experience and try to understand 
what roadblocks they hit first. No need to repeat the mistakes others 
already made.


- Johannes

On 01-Feb-21 18:37, Mandy Chung wrote:

Hi Johannes,

I believe you are aware of the prototype I'm working on:
https://github.com/mlchung/jdk/tree/method-invoke

My prototype so far replaces method and fields but not constructors 
yet.   You are welcome to contribute.


My main motivation of doing this is to get rid of the old clunky 
bytecode generator and core reflection will be built atop on method 
handles.   This would greatly simplify the work to add support for a new 
feature for example Valhalla primitive classes only in method handles.  
   I plan to keep the native method accessor  for startup use (or switch 
to method handles when module system is initialized).


Mandy

On 2/1/21 6:50 AM, Johannes Kuhn wrote:
While implementing a prototype for JDK-8242888 (Convert dynamic proxy 
to hidden classes) I came across the problem that hidden classes can't 
be mentioned in the constant pool, breaking the constructor for 
serialization.


To remedy that problem, I used a MHConstructorAccessor which delegates 
the actual work to MethodHandles - not unlike what JDK-6824466 suggests.


As there has been previous work in that area, (I am aware of at least 
3 independently developed prototypes for that bug/enchantment) I would 
like to ask a few questions around it:




1) What are the challenges?

From the bug I could infer, that it's cold start is slower than 
NativeMethodAccessor, but still faster than the generated (bytecode 
spinning) accessors.


2) Are there any roadblocks that prevent replacing the 
MethodAccessorGenerator with accessors that use MethodHandles?


From my limited tests, it appears to work well enough.

3) Should I try to implement it?



From my POV, replacing MethodAccessorGenerator with accessors that 
delegate to MethodHandles has a few benefits:


* Support for hidden classes. (Currently fallback to native accessors)
* Removal of MethodAccessorGenerator (which is old and clunky)

- Johannes




Re: JDK-6824466 java.lang.reflect.Method should use java.lang.invoke.MethodHandle

2021-02-01 Thread Johannes Kuhn




On 01-Feb-21 15:58, Remi Forax wrote:

- Mail original -

De: "Johannes Kuhn" 
À: "core-libs-dev" 
Envoyé: Lundi 1 Février 2021 15:50:51
Objet: JDK-6824466 java.lang.reflect.Method should use 
java.lang.invoke.MethodHandle



While implementing a prototype for JDK-8242888 (Convert dynamic proxy to
hidden classes) I came across the problem that hidden classes can't be
mentioned in the constant pool, breaking the constructor for serialization.

To remedy that problem, I used a MHConstructorAccessor which delegates
the actual work to MethodHandles - not unlike what JDK-6824466 suggests.

As there has been previous work in that area, (I am aware of at least 3
independently developed prototypes for that bug/enchantment) I would
like to ask a few questions around it:



1) What are the challenges?

 From the bug I could infer, that it's cold start is slower than
NativeMethodAccessor, but still faster than the generated (bytecode
spinning) accessors.

2) Are there any roadblocks that prevent replacing the
MethodAccessorGenerator with accessors that use MethodHandles?

 From my limited tests, it appears to work well enough.

3) Should I try to implement it?



 From my POV, replacing MethodAccessorGenerator with accessors that
delegate to MethodHandles has a few benefits:

* Support for hidden classes. (Currently fallback to native accessors)
* Removal of MethodAccessorGenerator (which is old and clunky)


Hi Johannes,
the native accessors doesn't play with loom (a C stack frame in the middle of 
the Java stack can not be moved) so it doesn't seem to be a good idea to rely 
on the native accessors for hidden classes.



- Johannes


Rémi




Thanks Rémi.

The problem here is that (according to Peter Levart tests), the cold use 
of a MHMethodAccessor is 11x as expensive as using the native accessor.


In some way, it sill makes sense to keep the native accessor around, at 
least during startup. On the other hand, I heard that there have been 
some improvements on the AppCDS w.r.t MethodHandles, but I'm out of the 
loop there.


An other problem with completely replacing the native accessors is some 
bootstrap problem - if certain flags are set (some of them are used to 
build the CDS), then the java.lang.invoke infrastructure tries to write 
stuff to System.out. But to initialize System.out, the charset has to be 
constructed, which relies on reflection.


I can see some potential in improving the initialization of the standard 
charset, but it's out of the scope here.


Apropos scope: I try to narrow the scope down to "replace 
MethodAccessorGenerator with accessors that delegate to MethodHandles".
Once this is done, then additional improvements can be made - including 
some that take loom into account. Or adding some @Stable/@ForceInline 
stuff so the JIT can better optimize reflective calls.


But currently (didn't look into the loom source) there are only two 
strategies: Native accessor (bad for loom) or generated (bytecode 
spinning, doesn't work with hidden classes). So, with loom and hidden 
classes you get the worst of both worlds. MethodHandles solve that.


- Johannes


JDK-6824466 java.lang.reflect.Method should use java.lang.invoke.MethodHandle

2021-02-01 Thread Johannes Kuhn
While implementing a prototype for JDK-8242888 (Convert dynamic proxy to 
hidden classes) I came across the problem that hidden classes can't be 
mentioned in the constant pool, breaking the constructor for serialization.


To remedy that problem, I used a MHConstructorAccessor which delegates 
the actual work to MethodHandles - not unlike what JDK-6824466 suggests.


As there has been previous work in that area, (I am aware of at least 3 
independently developed prototypes for that bug/enchantment) I would 
like to ask a few questions around it:




1) What are the challenges?

From the bug I could infer, that it's cold start is slower than 
NativeMethodAccessor, but still faster than the generated (bytecode 
spinning) accessors.


2) Are there any roadblocks that prevent replacing the 
MethodAccessorGenerator with accessors that use MethodHandles?


From my limited tests, it appears to work well enough.

3) Should I try to implement it?



From my POV, replacing MethodAccessorGenerator with accessors that 
delegate to MethodHandles has a few benefits:


* Support for hidden classes. (Currently fallback to native accessors)
* Removal of MethodAccessorGenerator (which is old and clunky)

- Johannes


Integrated: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base"

2021-02-01 Thread Johannes Kuhn
On Fri, 8 Jan 2021 09:38:40 GMT, Johannes Kuhn 
 wrote:

> Simple fix - one line change: 
> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
> 
> Most of the changes come from an additional test that fails without this fix:
> 
>  Error: Unable to load main class somelib.test.TestMain in module somelib
>   java.lang.IllegalAccessError: superclass access check failed: class 
> somelib.test.TestMain (in module somelib) cannot access class 
> java.lang.Object (in module java.base) because module java.base does not 
> export java.lang to module somelib
> 
> As described in JDK-8259395.
> You can view the output of the test without patch here: 
> https://github.com/DasBrain/jdk/runs/1668078245
> 
> Thanks to @AlanBateman for pointing out the right fix.

This pull request has now been integrated.

Changeset: cf942081
Author:Johannes Kuhn 
Committer: Alan Bateman 
URL:   https://git.openjdk.java.net/jdk/commit/cf942081
Stats: 454 lines in 11 files changed: 453 ins; 0 del; 1 mod

8259395: Patching automatic module with additional packages re-creates module 
without "requires java.base"

Reviewed-by: attila, alanb

-

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v6]

2021-01-31 Thread Johannes Kuhn
> Simple fix - one line change: 
> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
> 
> Most of the changes come from an additional test that fails without this fix:
> 
>  Error: Unable to load main class somelib.test.TestMain in module somelib
>   java.lang.IllegalAccessError: superclass access check failed: class 
> somelib.test.TestMain (in module somelib) cannot access class 
> java.lang.Object (in module java.base) because module java.base does not 
> export java.lang to module somelib
> 
> As described in JDK-8259395.
> You can view the output of the test without patch here: 
> https://github.com/DasBrain/jdk/runs/1668078245
> 
> Thanks to @AlanBateman for pointing out the right fix.

Johannes Kuhn has updated the pull request incrementally with one additional 
commit since the last revision:

  Renamed tests, to make it more clear what they should test.

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2000/files
  - new: https://git.openjdk.java.net/jdk/pull/2000/files/15a057d9..87b4a8ec

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk=2000=05
 - incr: https://webrevs.openjdk.java.net/?repo=jdk=2000=04-05

  Stats: 26 lines in 1 file changed: 0 ins; 0 del; 26 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2000.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2000/head:pull/2000

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


Integrated: 8259922 MethodHandles.collectArguments does not throw IAE if pos is outside the arity range

2021-01-22 Thread Johannes Kuhn
On Wed, 20 Jan 2021 18:29:00 GMT, Johannes Kuhn 
 wrote:

> Add explicit range check to `MethodHandles.collectArgumentsCheck`.  
> Added test case that exercises all cases.
> 
> This is a behavioral change, from throwing an unspecified exception to 
> throwing an IllegalArgumentException, as specified.  
> No spec change needed, as the IllegalArgumentException is already specified 
> to be thrown in those cases.
> 
> Feel free to suggest a better place for the tests.

This pull request has now been integrated.

Changeset: bf5e8015
Author:Johannes Kuhn 
Committer: Mandy Chung 
URL:   https://git.openjdk.java.net/jdk/commit/bf5e8015
Stats: 86 lines in 2 files changed: 86 ins; 0 del; 0 mod

8259922: MethodHandles.collectArguments does not throw IAE if pos is outside 
the arity range

Reviewed-by: mchung

-

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


Re: RFR: 8259922 MethodHandles.collectArguments does not throw IAE if pos is outside the arity range [v2]

2021-01-21 Thread Johannes Kuhn
On Fri, 22 Jan 2021 00:48:51 GMT, Johannes Kuhn 
 wrote:

>> Looks good.  What tests have you ran?
>
> On the latest commit, only my own test.  
> On the previous commit (4f74e2d) I did run the full tier1.
> 
> Currently a full test tier1 run on my machine and github actions is in 
> progress.

Tests did run successfully on my machine (win 64) and github actions.
Let me know if there should be additional tests that I should run.

-

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


Re: RFR: 8259922 MethodHandles.collectArguments does not follow its documentation [v2]

2021-01-21 Thread Johannes Kuhn
On Fri, 22 Jan 2021 00:44:12 GMT, Mandy Chung  wrote:

>> Johannes Kuhn has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   Implement suggestions by Mandy Chung.
>
> Looks good.  What tests have you ran?

On the latest commit, only my own test.  
On the previous commit (4f74e2d) I did run the full tier1.

Currently a full test tier1 run on my machine and github actions is in progress.

-

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


Re: RFR: 8259922 MethodHandles.collectArguments does not follow its documentation [v2]

2021-01-21 Thread Johannes Kuhn
> Add explicit range check to `MethodHandles.collectArgumentsCheck`.  
> Added test case that exercises all cases.
> 
> This is a behavioral change, from throwing an unspecified exception to 
> throwing an IllegalArgumentException, as specified.  
> No spec change needed, as the IllegalArgumentException is already specified 
> to be thrown in those cases.
> 
> Feel free to suggest a better place for the tests.

Johannes Kuhn has updated the pull request incrementally with one additional 
commit since the last revision:

  Implement suggestions by Mandy Chung.

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2171/files
  - new: https://git.openjdk.java.net/jdk/pull/2171/files/4f74e2df..f01fefaa

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk=2171=01
 - incr: https://webrevs.openjdk.java.net/?repo=jdk=2171=00-01

  Stats: 179 lines in 3 files changed: 82 ins; 95 del; 2 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2171.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2171/head:pull/2171

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


Re: RFR: 8259922 MethodHandles.collectArguments does not follow its documentation

2021-01-21 Thread Johannes Kuhn
On Thu, 21 Jan 2021 22:54:56 GMT, Mandy Chung  wrote:

>> Add explicit range check to `MethodHandles.collectArgumentsCheck`.  
>> Added test case that exercises all cases.
>> 
>> This is a behavioral change, from throwing an unspecified exception to 
>> throwing an IllegalArgumentException, as specified.  
>> No spec change needed, as the IllegalArgumentException is already specified 
>> to be thrown in those cases.
>> 
>> Feel free to suggest a better place for the tests.
>
> test/jdk/java/lang/invoke/8259922/TestMethodHandlesCollectArgs.java line 37:
> 
>> 35: import static org.testng.Assert.*;
>> 36: 
>> 37: public class TestMethodHandlesCollectArgs {
> 
> I suggest to rename this test in 
> `test/jdk/java/lang/invoke/MethodHandlesCollectArgsTest.java` matching 
> existing convention and `CollectArgsTest.java` is also fine with me.  The bug 
> ID is already in @bug and I find the directory with bug ID adds noise.

Yeah, still learning where to put tests.

-

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


RFR: 8259922 MethodHandles.collectArguments does not follow its documentation

2021-01-20 Thread Johannes Kuhn
Add explicit range check to `MethodHandles.collectArgumentsCheck`.  
Added test case that exercises all cases.

This is a behavioral change, from throwing an unspecified exception to throwing 
an IllegalArgumentException, as specified.  
No spec change needed, as the IllegalArgumentException is already specified to 
be thrown in those cases.

Feel free to suggest a better place for the tests.

-

Commit messages:
 - Fix tailing whitespace in in MethodHandles.java
 - Fix copyright yeahr in MethodHandles.java
 - Fix JDK-8259922
 - Fix JDK-8259922.

Changes: https://git.openjdk.java.net/jdk/pull/2171/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk=2171=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8259922
  Stats: 100 lines in 2 files changed: 99 ins; 0 del; 1 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2171.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2171/head:pull/2171

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v5]

2021-01-19 Thread Johannes Kuhn
> Simple fix - one line change: 
> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
> 
> Most of the changes come from an additional test that fails without this fix:
> 
>  Error: Unable to load main class somelib.test.TestMain in module somelib
>   java.lang.IllegalAccessError: superclass access check failed: class 
> somelib.test.TestMain (in module somelib) cannot access class 
> java.lang.Object (in module java.base) because module java.base does not 
> export java.lang to module somelib
> 
> As described in JDK-8259395.
> You can view the output of the test without patch here: 
> https://github.com/DasBrain/jdk/runs/1668078245
> 
> Thanks to @AlanBateman for pointing out the right fix.

Johannes Kuhn has updated the pull request incrementally with one additional 
commit since the last revision:

  Fix comment, and missing newline in module-info.java

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2000/files
  - new: https://git.openjdk.java.net/jdk/pull/2000/files/fc3b2ac0..15a057d9

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk=2000=04
 - incr: https://webrevs.openjdk.java.net/?repo=jdk=2000=03-04

  Stats: 7 lines in 5 files changed: 0 ins; 2 del; 5 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2000.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2000/head:pull/2000

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v4]

2021-01-19 Thread Johannes Kuhn
> Simple fix - one line change: 
> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
> 
> Most of the changes come from an additional test that fails without this fix:
> 
>  Error: Unable to load main class somelib.test.TestMain in module somelib
>   java.lang.IllegalAccessError: superclass access check failed: class 
> somelib.test.TestMain (in module somelib) cannot access class 
> java.lang.Object (in module java.base) because module java.base does not 
> export java.lang to module somelib
> 
> As described in JDK-8259395.
> You can view the output of the test without patch here: 
> https://github.com/DasBrain/jdk/runs/1668078245
> 
> Thanks to @AlanBateman for pointing out the right fix.

Johannes Kuhn has updated the pull request incrementally with one additional 
commit since the last revision:

  Implement more tests.

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2000/files
  - new: https://git.openjdk.java.net/jdk/pull/2000/files/7c2ed088..fc3b2ac0

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk=2000=03
 - incr: https://webrevs.openjdk.java.net/?repo=jdk=2000=02-03

  Stats: 388 lines in 10 files changed: 316 ins; 54 del; 18 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2000.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2000/head:pull/2000

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v3]

2021-01-19 Thread Johannes Kuhn
On Tue, 19 Jan 2021 16:14:51 GMT, Alan Bateman  wrote:

>>> 
>>> 
>>> This issue requires a Reviewer from someone working in this area. Please do 
>>> not sponsor or integrate until that review has been done.
>> 
>> Ok, increased the number of required reviewers to 2.  
>> Hope that was the right move, as I don't see any other way to undo 
>> /integrate.
>
> Finally getting back to this. The update to ModulePatcher.java is good. Test 
> coverage needs discussion. There are four scenarios where test coverage is 
> lacking:
> 
> 1. automatic module on the module path, patched to override or augment 
> classes/resources
> 2. automatic module on the module path, patched to add new packages
> 3. automatic module as the initial module, patched to override or augment 
> classes/resources
> 4. automatic module as the initial module, patched to add new packages
> 
> The patch adds automatic/PatchTest.java so it's adding test coverage for 4. 
> We should probably rename it to leave room for the other tests, or else 
> create it so that additional test coverage can be added. I assume the test 
> was copied from another test as there are a few left overs, e.g. `@modules 
> java.script` but the test does not use this module. I don't want to expand 
> the scope of this PR too much but I think we should at least cover 3 and 4 in 
> the test.

Thanks @AlanBateman, I now implemented a few more tests.  
They should cover all four cases you described.

-

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


Re: A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

2021-01-18 Thread Johannes Kuhn

Thanks Mandy.

Yes, @CS is a complicated beast.
I also implemented a part of JDK-6824466 for my "proxies should use 
hidden classes prototype". (Only for the "constructor for 
serialization", as hidden classes can't be mentioned in the constant pool.)


For the @CS method that can be called virtually - 
Thread.getContextClassLoader, I thought about those two interfaces:


interface GetCCLClassLoader {ClassLoader getContextClassLoader(); }
interface GetCCLObject {Object getContextClassLoader(); }

Insight: If a class extends Thread and implements GetCCLObject, javac 
will add a bridge method - which is the caller now. Have to think more 
about what this actually means.


The entire topic is very complex - but my current believe is that 
JDK-6824466 is a basic building block for a lot of other work in that 
area. It also has quite a few prototypes that have been developed 
independently - suggesting that it is indeed a basic building block.


I did a quick look though your prototype, one question I could not 
answer was "what prevents me from naming my hidden class 
Something$$InjectedInvoker?".


I will try to dig deeper into that, sure. I don't think that there will 
be any fully satisfying solution in the next months. And then I have to 
convince people that those changes don't expose any security issues - 
which will be quite hard.


But if you have some starter bugs that I could fix, let me know, might 
help to get some reputation and familiarity with the entire process.


Thank you for your time listening to my ideas, I appreciate it :).

- Johannes

On 18-Jan-21 22:52, Mandy Chung wrote:

Hi Johannes,

There has been a couple of the prototypes regarding @CS methods (Alan 
did one and I did another) in the context of JDK-6824466. There are lots 
of security consideration regarding @CS methods. You are welcome to go 
deeper in that area.  If you are looking for starter bugs to fix, that 
won't be a quick patch.


I also came up with a patch for JDK-8013527 when working on 
JDK-6824466.  It's buried in 
https://github.com/openjdk/jdk/compare/master...mlchung:method-invoke. I 
will extract that fix and post a PR on my proposed fix.


Mandy

On 1/16/21 10:07 AM, Johannes Kuhn wrote:

After digging though the JBS, I found this comment from John Rose[1].

I like the general idea, but I don't think it's necessary to use a 
native method as stub. Instead it could be written like this:


class Class {
  @CallerSensitive
  @ForceInline
  public static Class forName(String name) {
  return forName(name, Reflection.getCallerClass());
  }
  private static Class forName(String name, Class caller) {
  // original implementation
  }
}

By doing this, binding to the caller could be done by returning a 
MethodHandle that actually calls the private method - with the lookup 
class injected as argument (MethodHandles.insertArguments).


Problem are methods that could be virtually invoked 
(getContextClassLoader). Therefore it might be useful to keep the old 
binding logic around. It also reduces the number of places where this 
change has to be done - it's only required for the 
hyper-@CallerSensitive methods.


I will try to write a prototype that demonstrates that this approach 
is feasible.


- Johannes

[1]: 
https://bugs.openjdk.java.net/browse/JDK-8020968?focusedCommentId=13611844=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-13611844


On 09-Dec-20 21:09, Johannes Kuhn wrote:

On 09-Dec-20 19:44, Mandy Chung wrote:



On 12/8/20 6:02 PM, Johannes Kuhn wrote:

There are a lot of things to consider when trying to fix JDK-8013527.


Exactly in particular security implication!  What is clear is that 
the expected lookup class should not be the injected class.   The 
key message here is that we can't fix JDK-8257874 until we fix 
JDK-8013527 unfortunately.


Mandy


Yeah, if JDK-8013527 is fixed it might fix JDK-8257874 as a byproduct.
If Lookup.lookup() can determine the original caller, then 
Field.set*/Method.invoke could do the same.
Special care has to be taken that no other class could spoof such an 
injected invoker.


Too complicated for me :). JDK-8013527 needs a sound design to 
approach fixing it IMHO.


- Johannes





Trying to fix JDK-8013527 - 1st Prototype

2021-01-17 Thread Johannes Kuhn
JDK-8013527[1] has somehow become the umbrella bug for "Using 
MethodHandles to call caller sensitive methods leads to interesting 
results".


To recap: A caller sensitive method knows about who called it, and can 
behave differently when called from an other context.

Examples are: Class.forName, MethodHandles.lookup, Method.invoke...

A MethodHandle on the other hand should not be caller sensitive.
To archive this, a MethodHandle will "bind" the lookup class as caller 
for caller sensitive methods.


This is currently done by injecting a hidden class (InjectedInvoker" 
that acts as a trampoline for calling caller sensitive methods.


This injected invoker shares many properties of the original caller:
Same ClassLoader, same Module, same Package, same ProtectionDomain, but 
it's not the same class or a nestmate of it.


For caller sensitive methods that do look at more than just the injected 
invoker, this leads to "unexpected" results when called through a 
MethodHandle:


* MethodHandles.lookup() returns a full privileged lookup for the 
injected invoker.
* jlr.Field.get*/set*, jlr.Constructor.newInstance, jlr.Method.invoke 
may fail with an IllegalAccessException if the target is private. See 
JDK-8257874[2].


---

After reading one of John Rose's comments[3], I thought that this might 
be a way to solve this general problem.


So I implemented some of it here[4].

The basic idea is that there is a private overload of the caller 
sensitive method which accepts the caller as a tailing argument.


The good news:
* tier1 Tests pass.
* ((Lookup) lookup.findStatic(MethodHandles.class, "lookup", 
MethodType.methodType(Lookup.class)).invokeExact()).lookupClass() == 
lookup.lookupClass();

* JDK-8257874 can't be reproduced with Field.* or Constructor.
* Performance is likely better. (InjectedInvoker collects all arguments 
into an Object[].)


The bad news:
* If you use a MethodHandle to call Method.invoke for a caller sensitive 
method, then you can still observe the injected invoker.


---

Moving forward, there are 3 ways:
1. Do nothing. Won't fix any bug.
2. Use the current prototype, and accept Method.invoke is odd when 
calling it through a MethodHandle.

3. Go all in:
  * Require **every** caller sensitive method to have a private overload.
  * Method.invoke will also use that private overload.

The problems with the 3rd approach are:
  * What about methods that can be called virtually? 
(Thread.getContextClassLoader())
  * Requires a few changes to MethodAccessor. Maybe implementing 
JDK-6824466[5] first?

  * What about methods that do stack walks?

I have to think more about the problems listed above - but maybe you 
have some input that could help me on that.


- Johannes


[1]: https://bugs.openjdk.java.net/browse/JDK-8013527
[2]: https://bugs.openjdk.java.net/browse/JDK-8257874
[3]: 
https://bugs.openjdk.java.net/browse/JDK-8020968?focusedCommentId=13611844=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-13611844

[4]: https://github.com/openjdk/jdk/pull/2117/files
[5]: https://bugs.openjdk.java.net/browse/JDK-6824466


Re: A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

2021-01-16 Thread Johannes Kuhn

After digging though the JBS, I found this comment from John Rose[1].

I like the general idea, but I don't think it's necessary to use a 
native method as stub. Instead it could be written like this:


class Class {
  @CallerSensitive
  @ForceInline
  public static Class forName(String name) {
  return forName(name, Reflection.getCallerClass());
  }
  private static Class forName(String name, Class caller) {
  // original implementation
  }
}

By doing this, binding to the caller could be done by returning a 
MethodHandle that actually calls the private method - with the lookup 
class injected as argument (MethodHandles.insertArguments).


Problem are methods that could be virtually invoked 
(getContextClassLoader). Therefore it might be useful to keep the old 
binding logic around. It also reduces the number of places where this 
change has to be done - it's only required for the 
hyper-@CallerSensitive methods.


I will try to write a prototype that demonstrates that this approach is 
feasible.


- Johannes

[1]: 
https://bugs.openjdk.java.net/browse/JDK-8020968?focusedCommentId=13611844=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-13611844


On 09-Dec-20 21:09, Johannes Kuhn wrote:

On 09-Dec-20 19:44, Mandy Chung wrote:



On 12/8/20 6:02 PM, Johannes Kuhn wrote:

There are a lot of things to consider when trying to fix JDK-8013527.


Exactly in particular security implication!  What is clear is that the 
expected lookup class should not be the injected class.   The key 
message here is that we can't fix JDK-8257874 until we fix JDK-8013527 
unfortunately.


Mandy


Yeah, if JDK-8013527 is fixed it might fix JDK-8257874 as a byproduct.
If Lookup.lookup() can determine the original caller, then 
Field.set*/Method.invoke could do the same.
Special care has to be taken that no other class could spoof such an 
injected invoker.


Too complicated for me :). JDK-8013527 needs a sound design to approach 
fixing it IMHO.


- Johannes



Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v3]

2021-01-11 Thread Johannes Kuhn
On Mon, 11 Jan 2021 14:13:47 GMT, Alan Bateman  wrote:

> 
> 
> This issue requires a Reviewer from someone working in this area. Please do 
> not sponsor or integrate until that review has been done.

Ok, increased the number of required reviewers to 2.  
Hope that was the right move, as I don't see any other way to undo /integrate.

-

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v3]

2021-01-11 Thread Johannes Kuhn
On Mon, 11 Jan 2021 14:06:12 GMT, Attila Szegedi  wrote:

>> Johannes Kuhn has updated the pull request incrementally with one additional 
>> commit since the last revision:
>> 
>>   Add a missing pesky newline.
>
> Marked as reviewed by attila (Reviewer).

Thanks @szegedi for reviewing this.

-

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v3]

2021-01-10 Thread Johannes Kuhn
> Simple fix - one line change: 
> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
> 
> Most of the changes come from an additional test that fails without this fix:
> 
>  Error: Unable to load main class somelib.test.TestMain in module somelib
>   java.lang.IllegalAccessError: superclass access check failed: class 
> somelib.test.TestMain (in module somelib) cannot access class 
> java.lang.Object (in module java.base) because module java.base does not 
> export java.lang to module somelib
> 
> As described in JDK-8259395.
> You can view the output of the test without patch here: 
> https://github.com/DasBrain/jdk/runs/1668078245
> 
> Thanks to @AlanBateman for pointing out the right fix.

Johannes Kuhn has updated the pull request incrementally with one additional 
commit since the last revision:

  Add a missing pesky newline.

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2000/files
  - new: https://git.openjdk.java.net/jdk/pull/2000/files/73ac7fde..7c2ed088

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk=2000=02
 - incr: https://webrevs.openjdk.java.net/?repo=jdk=2000=01-02

  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2000.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2000/head:pull/2000

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base" [v2]

2021-01-10 Thread Johannes Kuhn
> Simple fix - one line change: 
> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
> 
> Most of the changes come from an additional test that fails without this fix:
> 
>  Error: Unable to load main class somelib.test.TestMain in module somelib
>   java.lang.IllegalAccessError: superclass access check failed: class 
> somelib.test.TestMain (in module somelib) cannot access class 
> java.lang.Object (in module java.base) because module java.base does not 
> export java.lang to module somelib
> 
> As described in JDK-8259395.
> You can view the output of the test without patch here: 
> https://github.com/DasBrain/jdk/runs/1668078245
> 
> Thanks to @AlanBateman for pointing out the right fix.

Johannes Kuhn has updated the pull request incrementally with one additional 
commit since the last revision:

  Move tests to test/jdk/tools/launcher/modules/patch/automatic.

-

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/2000/files
  - new: https://git.openjdk.java.net/jdk/pull/2000/files/bf715a8c..73ac7fde

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk=2000=01
 - incr: https://webrevs.openjdk.java.net/?repo=jdk=2000=00-01

  Stats: 176 lines in 4 files changed: 114 ins; 61 del; 1 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2000.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2000/head:pull/2000

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


Re: RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base"

2021-01-10 Thread Johannes Kuhn
On Sun, 10 Jan 2021 15:14:31 GMT, Alan Bateman  wrote:

>> Simple fix - one line change: 
>> https://openjdk.github.io/cr/?repo=jdk=2000=00#sdiff-0.
>> 
>> Most of the changes come from an additional test that fails without this fix:
>> 
>>  Error: Unable to load main class somelib.test.TestMain in module somelib
>>  java.lang.IllegalAccessError: superclass access check failed: class 
>> somelib.test.TestMain (in module somelib) cannot access class 
>> java.lang.Object (in module java.base) because module java.base does not 
>> export java.lang to module somelib
>> 
>> As described in JDK-8259395.
>> You can view the output of the test without patch here: 
>> https://github.com/DasBrain/jdk/runs/1668078245
>> 
>> Thanks to @AlanBateman for pointing out the right fix.
>
> test/jdk/jdk/modules/scenarios/automaticmodules/RunWithAutomaticModules.java 
> line 186:
> 
>> 184: }
>> 185: 
>> 186: /**
> 
> The update to ModulePatcher is fine,  that was an oversight that was missed 
> because it's a real corner to have an automatic module be the initial module 
> and patch it to add additional packages at the same time.
> 
> The tests for --patch-module are in jdk/tools/launcher/modules/patch. I was 
> planning to add tests there for patching automatic modules when I created the 
> issue (I didn't know you were going to create a PR for it).

Choosing the right place for the test was one of the harder parts.

I did choose automaticmodules because it already has most of the necessary 
machinery already in place.  
But I will move the tests to jdk/tools/launcher/modules/patch.

And making a PR was a shortcut reaction - "Hey, I could do this".

-

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


RFR: JDK-8259395 Patching automatic module with additional packages re-creates module without "requires java.base"

2021-01-08 Thread Johannes Kuhn
Simple fix, complex test case.

Thanks to @AlanBateman for pointing out the right fix.

-

Commit messages:
 - * Minor cleanup.
 - * Fix Whitespace V2
 - * Fix whitespace
 - * Fix JDK-8259395 - test now passes
 - Merge branch 'master' of https://github.com/openjdk/jdk into JDK-8259395
 - * Add failing tests for JDK-8259395

Changes: https://git.openjdk.java.net/jdk/pull/2000/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk=2000=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8259395
  Stats: 142 lines in 4 files changed: 140 ins; 0 del; 2 mod
  Patch: https://git.openjdk.java.net/jdk/pull/2000.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/2000/head:pull/2000

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


Re: java.io.Console (was: Is SharedSecrets thread-safe?)

2021-01-04 Thread Johannes Kuhn

This brings up some stuff I wanted to mention for some time:

* Console.cs is one of the fields projects like JRuby hack into (at 
least in the past). My guess is that they handle encodings in Ruby, and 
not using the Java facilities for that.


The fact that it is also exported as shared secret for some unrelated 
stuff (sun.security.util) shows that there might be a need for a 
supported, public API.


* java.io.Console has a nice API - but it only works (at least on 
Windows) if there is indeed a console attached. It usually doesn't work 
inside an IDE.


Is there an interest to allow IDEs to create their own Console 
implementation, exposed through SPI?
I would volunteer to write the spec and a patch, but there should be 
some general interest for this - as someone has to sponsor that.
(And as a fair warning: It would be my first bigger contribution to 
OpenJDK.)


- Johannes

On 04-Jan-21 22:48, Peter Levart wrote:

Hello 99206970363698485155,


Thanks for these pointers. I would prefer to untangle those knots one at 
a time, if you don't mind, since some of them touch other parts of code 
while this change to SharedSecrets is pretty straightforward and localized.



Regards, Peter


On 12/31/20 6:25 PM, some-java-user-99206970363698485...@vodafonemail.de 
wrote:

Hello Peter,
the changes look good, however there might be more to consider:

- `jdk.internal.access.SharedSecrets.getJavaLangRefAccess()`
   Might be good to add a comment there or for 
`java.lang.ref.Reference` that it is (hopefully?)
   initialized during JVM start-up. Similar to the comment for 
`AccessibleObject` which states

   that it is initialized in "initPhase1".
   Currently without special knowledge about JVM start-up, it is not 
obvious that this construct

   is safe.

- `java.io.Console.cons`
   This is pretty brittle. It is currently only thread-safe because 
the only accessor is
   `System.console()` which has its own synchronization. However, I 
doubt that the author was aware

   that `Console.cons` on its own is not thread-safe.
   In general, why is there lazy initialization twice? Once in 
`System.console()` and then in the
   accessor for `Console.cons`. In my opinion *only* `java.io.Console` 
should have the lazy
   initialization logic (with proper synchronization!) and make sure 
that only one `Console` instance

   exists.

- `jdk.internal.access.JavaIOAccess.charset()`
   The implementation of this one is extremely brittle. While it 
documents that the `Password` class
   calling it will make sure that `System.console()` has been called 
before, in that `Password` class
   there is not such notice, so it could easily happen that someone 
breaks this at a later point.
   Additionally the field `Console.cs` it accesses is not `final`, 
making it even more brittle.


   In my opinion there should be two changes:
   1. Change `JavaIOAccess.charset()` -> `charset(Console)`, which 
then accesses the charset from that

  Console argument.
  This enforces that the user of the access already has the 
Console initialized and indirectly

  establishes the happens-before relationship for `Console.cs`.
   2. The Console class should have the following fields `final`:
  readLock, writeLock, reader, out, pw, formatter, cs
  For `cs` this would merely require introducing a local variable.

   In general `sun.security.util.Password.convertToBytes(char[])` is 
problematic because it makes
   passwords unportable when one OS uses a different terminal encoding 
than another.
   The cleaner backward compatible solution might be to simply block 
all non-ASCII chars (i.e. throw

   exception for them)?
   This would break for all existing users which used non-ASCII chars 
or where their terminal has an
   encoding not based on ASCII, but these users might already have 
different problems due to the

   existing implementation.

- `jdk.internal.access.SharedSecrets.setJavaAWTAccess(JavaAWTAccess)`
   Might have to establish a happens-before relationship for 
`getJavaAWTAccess()` because caller
   appears to expect a `JavaAWTAccess` in case respective class has 
been loaded.


   On a side note here: The implementation of that access appears to 
contain redundant code:
   
https://github.com/openjdk/jdk/blob/8435f0daf2413a4c17578dd288e093fe006b3880/src/java.desktop/share/classes/sun/awt/AppContext.java#L866 

   The null check there makes no sense because `ecx` is always null at 
that point.


- 
`jdk.internal.access.SharedSecrets.setJavaAWTFontAccess(JavaAWTFontAccess)` 

   This seems to be rather brittle as well because its callers check 
whether the access has already

   been initialized.
   Additionally this seems to be more complicated than it has to be: 
It appears to be simpler to have
   `SharedSecrets` initialize the access by initializing only 
`NumericShaper` (or `TextAttribute`,
   ultimately does not matter which class from that package is used) 
when `getJavaAWTFontAccess()` is

   called. The 

Re: RFR: 8198540: Dynalink leaks memory when generating type converters

2021-01-02 Thread Johannes Kuhn
On Sat, 2 Jan 2021 14:45:51 GMT, Attila Szegedi  wrote:

> _(NB: For this leak to occur, an application needs to be either creating and 
> discarding linkers frequently, or creating and discarding class loaders 
> frequently while creating Dynalink type converters for classes in them. 
> Neither is typical usage, although they can occur in dynamic code loading 
> environments such as OSGi.)_
> 
> I'll explain this one in a bit more detail. Dynalink's creates and caches 
> method handles for language-specific conversions between types. Each 
> conversion is thus characterized by a `Class` object representing the type 
> converted from, and a `Class` object representing the type converted to, thus 
> they're keyed by a pair of `(Class, Class)`. Java API provides the excellent 
> `ClassValue` class for associating values with a single class, but it lacks 
> the – admittedly more niche – facility for associating a value with a pair of 
> classes. I originally solved this problem using something that looks like a 
> `ClassValue, T>>`. I say "looks like" because Dynalink has a 
> specialized `ClassMap` class that works like `Map, T>` but it also 
> goes to some pains to _not_ establish strong references from a class loader 
> to either its children or to unrelated class loaders, for obvious reasons.
> 
> Surprisingly, the problem didn't lie in there, though. The problem was in the 
> fact that `TypeConverterFactory` used `ClassValue` objects that were its 
> non-static anonymous inner classes, and further the values they computed were 
> also of non-static anonymous inner classes. Due to the way `ClassValue` 
> internals work, this led to the `TypeConverterFactory` objects becoming 
> anchored in a GC root of `Class.classValueMap` through the synthetic `this$0` 
> reference chains in said inner classes… talk about non-obvious memory leaks. 
> (I guess there's a lesson in there about not using `ClassValue` as an 
> instance field, but there's a genuine need for them here, so…)
> 
> … so the first thing I did was I deconstructed all those anonymous inner 
> classes into named static inner classes, and ended up with something that 
> _did_ fix the memory leak (yay!) but at the same time there was a bunch of 
> copying of constructor parameters from outer classes into the inner classes, 
> the whole thing was very clunky with scary amounts of boilerplate. I felt 
> there must exist a better solution.
> 
> And it exists! I ended up replacing the `ClassValue>` construct 
> with a ground-up implementation of `BiClassValue`, representation of 
> lazily computed values associated with a pair of types. This was the right 
> abstraction the `TypeConverterFactory` code needed all along. 
> `BiClassValue` is also not implemented as an abstract class but rather it 
> is a final class and takes a `BiFunction, Class, T>` for 
> computation of its values, thus there's never a risk of making it an 
> instance-specific inner class (well, you still need to be careful with the 
> bifunction lambda…) It also has an even better solution for avoiding strong 
> references to child class loaders.
> 
> And that's why I'm not submitting here the smallest possible point fix to the 
> memory leak, but rather a slightly larger one that architecturally fixes it 
> the right way.
> 
> There are two test classes, they test subtly different scenarios. 
> `TypeConverterFactoryMemoryLeakTest` tests that when a `TypeConverterFactory` 
> instance becomes unreachable, all method handles it created also become 
> eligible for collection. `TypeConverterFactoryRetentionTests` on the other 
> hand test that the factory itself won't prevent class loaders from being 
> collected by virtue of creating converters for them.

Just a small suggestion using `MethodHandles.empty` instead of 
`MethodHandles.constant().asType().dropArguments()`.

test/jdk/jdk/dynalink/TypeConverterFactoryRetentionTests.java line 65:

> 63: // Never meant to be invoked, just a dummy MH that conforms 
> to the expected type.
> 64: MethodHandle result = MethodHandles.constant(Object.class, 
> null).asType(MethodType.methodType(targetType));
> 65: result = MethodHandles.dropArguments(result, 0, sourceType);

Suggestion:

MethodHandle result = 
MethodHandles.empty(MethodType.methodType(targetType, sourceType));

test/jdk/jdk/dynalink/TypeConverterFactoryMemoryLeakTest.java line 70:

> 68: // Never meant to be invoked, just a dummy MH that conforms 
> to the expected type.
> 69: MethodHandle result = MethodHandles.constant(Object.class, 
> null).asType(MethodType.methodType(targetType));
> 70: result = MethodHandles.dropArguments(result, 0, sourceType);

Suggestion:

MethodHandle result = 
MethodHandles.empty(MethodType.methodType(targetType, sourceType));

-

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


Re: RFR: 8198540: Dynalink leaks memory when generating type converters

2021-01-02 Thread Johannes Kuhn
On Sat, 2 Jan 2021 14:45:51 GMT, Attila Szegedi  wrote:

> _(NB: For this leak to occur, an application needs to be either creating and 
> discarding linkers frequently, or creating and discarding class loaders 
> frequently while creating Dynalink type converters for classes in them. 
> Neither is typical usage, although they can occur in dynamic code loading 
> environments such as OSGi.)_
> 
> I'll explain this one in a bit more detail. Dynalink's creates and caches 
> method handles for language-specific conversions between types. Each 
> conversion is thus characterized by a `Class` object representing the type 
> converted from, and a `Class` object representing the type converted to, thus 
> they're keyed by a pair of `(Class, Class)`. Java API provides the excellent 
> `ClassValue` class for associating values with a single class, but it lacks 
> the – admittedly more niche – facility for associating a value with a pair of 
> classes. I originally solved this problem using something that looks like a 
> `ClassValue, T>>`. I say "looks like" because Dynalink has a 
> specialized `ClassMap` class that works like `Map, T>` but it also 
> goes to some pains to _not_ establish strong references from a class loader 
> to either its children or to unrelated class loaders, for obvious reasons.
> 
> Surprisingly, the problem didn't lie in there, though. The problem was in the 
> fact that `TypeConverterFactory` used `ClassValue` objects that were its 
> non-static anonymous inner classes, and further the values they computed were 
> also of non-static anonymous inner classes. Due to the way `ClassValue` 
> internals work, this led to the `TypeConverterFactory` objects becoming 
> anchored in a GC root of `Class.classValueMap` through the synthetic `this$0` 
> reference chains in said inner classes… talk about non-obvious memory leaks. 
> (I guess there's a lesson in there about not using `ClassValue` as an 
> instance field, but there's a genuine need for them here, so…)
> 
> … so the first thing I did was I deconstructed all those anonymous inner 
> classes into named static inner classes, and ended up with something that 
> _did_ fix the memory leak (yay!) but at the same time there was a bunch of 
> copying of constructor parameters from outer classes into the inner classes, 
> the whole thing was very clunky with scary amounts of boilerplate. I felt 
> there must exist a better solution.
> 
> And it exists! I ended up replacing the `ClassValue>` construct 
> with a ground-up implementation of `BiClassValue`, representation of 
> lazily computed values associated with a pair of types. This was the right 
> abstraction the `TypeConverterFactory` code needed all along. 
> `BiClassValue` is also not implemented as an abstract class but rather it 
> is a final class and takes a `BiFunction, Class, T>` for 
> computation of its values, thus there's never a risk of making it an 
> instance-specific inner class (well, you still need to be careful with the 
> bifunction lambda…) It also has an even better solution for avoiding strong 
> references to child class loaders.
> 
> And that's why I'm not submitting here the smallest possible point fix to the 
> memory leak, but rather a slightly larger one that architecturally fixes it 
> the right way.
> 
> There are two test classes, they test subtly different scenarios. 
> `TypeConverterFactoryMemoryLeakTest` tests that when a `TypeConverterFactory` 
> instance becomes unreachable, all method handles it created also become 
> eligible for collection. `TypeConverterFactoryRetentionTests` on the other 
> hand test that the factory itself won't prevent class loaders from being 
> collected by virtue of creating converters for them.

test/jdk/jdk/dynalink/TypeConverterFactoryMemoryLeakTest.java line 69:

> 67: public GuardedInvocation convertToType(Class sourceType, 
> Class targetType, Supplier lookupSupplier) {
> 68: // Never meant to be invoked, just a dummy MH that conforms 
> to the expected type.
> 69: MethodHandle result = MethodHandles.constant(Object.class, 
> null).asType(MethodType.methodType(targetType));

Suggestion:

MethodHandle result = MethodHandles.zero(targetType);

test/jdk/jdk/dynalink/TypeConverterFactoryRetentionTests.java line 64:

> 62: public GuardedInvocation convertToType(Class sourceType, 
> Class targetType, Supplier lookupSupplier) {
> 63: // Never meant to be invoked, just a dummy MH that conforms 
> to the expected type.
> 64: MethodHandle result = MethodHandles.constant(Object.class, 
> null).asType(MethodType.methodType(targetType));

Suggestion:

MethodHandle result = MethodHandles.zero(targetType);

-

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


Re: Is SharedSecrets thread-safe?

2020-12-29 Thread Johannes Kuhn
It's a bit more complicated - after all we are talking about the memory 
model and class loading.


There are some shared secrets that can be loaded later (e.g. AWT), when 
Threads are there.


The field is only set in one single place inside the JDK, so we are 
talking about 3 scenarios:


* The class is not yet loaded - the field is null, call 
ensureClassInitialized - which executes the class initializer on the 
current thread. A subsequent read of the field must be visible - as 
actions performed in the thread appear to be sequential for that thread.


* The class has been successfully loaded, everything relating to that is 
visible.


* The class is currently initialized by an other thread:
  * The first load of the field yields null - ensureClassInitialized 
blocks until the class has been loaded.

  * The first load yields something different than null.
The question now is: can the second load yield the previous value?
That is: can a field revert to it's original value?
Other fields may not be visible yet (except if they have been frozen).
So the big question is: can the second read return null after the 
first has found it to be a non-null value?


After reading the "Double checked locking is broken"[1] declaration 
again - it says that it does work for primitive values that can't be 
teared. The problem seems to be that the field of the referenced objects 
are not yet constructed.


The good news: the implementations of the shared secrets don't have 
fields. The better news: reference assignment also can't be teared.


- Johannes

[1]: https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

On 29-Dec-20 18:53, Hans Boehm wrote:



On Tue, Dec 29, 2020 at 5:56 AM Johannes Kuhn <mailto:i...@j-kuhn.de>> wrote:

 >
 > Depends on what `initialize()` is.
 >
 > If it (at least) reads a volatile field, then the compiler can't reorder
 > the second read before the first.
 >
 > - Johannes
I disagree with this claim. I have no idea whether concurrency is 
possible here, so it may not matter. See below.


 >
 > On 29-Dec-20 14:42, 
some-java-user-99206970363698485...@vodafonemail.de 
<mailto:some-java-user-99206970363698485...@vodafonemail.de>

 > wrote:
 > > Hello,
 > > the class `jdk.internal.access.SharedSecrets` provides getter 
methods which all look similar to this:

 > > ```
 > > if (static_field == null) {
 > >    initialize();
 > > }
 > > return static_field;
 > > ```

If static_field is not volatile, and set concurrently, then the first 
read of static_field may return non-null and the second null, without 
initialize() even being executed. The Java memory model does not prevent 
reordering of non-volatile reads from the same field (for good reason).


Even if initialize() is executed and performs a volatile read, this 
reasoning doesn't hold. The initial static_field read may be delayed 
past the volatile read inside the conditional and hence, at least 
theoretically, past the second read. Control dependencies don't order 
reads, either in Java, or in modern weakly-ordered architectures with 
branch prediction. This doesn't matter if initialize() sets static_field.


This all assumes that having two threads call initialize() is OK.

Java code with data races is extremely tricky and rarely correct.

Hans


Re: Is SharedSecrets thread-safe?

2020-12-29 Thread Johannes Kuhn

Depends on what `initialize()` is.

If it (at least) reads a volatile field, then the compiler can't reorder 
the second read before the first.


- Johannes

On 29-Dec-20 14:42, some-java-user-99206970363698485...@vodafonemail.de 
wrote:

Hello,
the class `jdk.internal.access.SharedSecrets` provides getter methods which all 
look similar to this:
```
if (static_field == null) {
   initialize();
}
return static_field;
```

However, neither the static fields are `volatile` nor are the getter methods 
synchronized. So if my
understanding of the Java Memory Model is correct, the compiler is free to 
reorder the two static
field reads. So it is in theory possible that the first read yields a 
non-`null` value, but the
second read yields a `null` value which leads to incorrect behavior (for 
further reading [1]).

It is probably rather unlikely that this actually happens because 
`SharedSecrets` is in most cases
accessed from static initializers (which are only run once) and because not 
many classes access the
same `SharedSecrets` fields.

Is this analysis correct or did I forget to consider parts of the Memory Model 
logic, or is there
some JVM magic I am missing?

Kind regards

[1] 
https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#wishful-benign-is-resilient



Re: JDK-8229959/JDK-8242888 Prototype for j.l.r.Proxy with hidden classes & class data

2020-12-17 Thread Johannes Kuhn



Thanks Mandy,

Appreciate your feedback, as always.

On 18-Dec-20 0:01, Mandy Chung wrote:

Hi Johannes,

I'm glad to see this prototype.  Converting dynamic proxy to hidden 
classes has a few challenges as JDK-8242888 describes.


1) the serialization specification w.r.t. dynamic proxies


Serialization is a must have, because annotation are implemented using 
dynamic proxies.

But I made it work in my prototype.
The serialization format uses a special PROXYCLASSDESC - basically an 
array of CLASSDESC of all implemented interfaces of the dynamic proxy. 
It then asks j.l.r.Proxy for the proxy class that implements those 
interfaces.


The issue I run in was the way the proxy class is instantiated. 
ReflectionFactory::newConstructorForSerialization did spin a class that 
referenced the expected type by it's binary name.
To avoid that, I created a MethodHandleConstructorAccessor, that just 
delegates call to a MethodHandle. j.l.invoke internals are very powerful 
and can do such shenanigans.


In the end, I think no specification change is necessary, at least for 
that part. (Other parts may need one - the jshell test shows that such a 
change is visible in the stack trace)


We need to look into the implication to the specification and whether 
the default serialization mechanism should (or should not) support 
dynamic proxies if it's defined as hidden classes.


2) how to get a Lookup on a package for the dynamic proxy class to be 
injected in without injecting a shim class (i.e. your anchor class)?


Frameworks don't always have the access to inject a class in a package 
defined to a class loader.  Dynamic proxies are a use case to determine 
what functionality is needed to avoid spinning a shim class.



That topic certainly needs a lot more thought.

What are the requirements, what kind of frameworks exist, what do they 
need...


For the dynamic proxy case: it just needs two unique packages per 
ClassLoader. Names don't matter, as long as they don't clash with 
anything else.


Currently they don't clash, because the specification says: don't name 
your packages this way.


But a hidden class (and Lookup.defineClass) will always have package 
private access to your package. This may or may not be intended by a 
framework - especially if it compiles user code, like xerces or clojure.




3) protection domain

The current spec of Proxy class is defined with null protection domain 
(same protection domain as the bootstrap class loader). 
Lookup::defineHiddenClass defines the hidden class in the same 
protection domain as the defining class loader.  This requires to 
understand deeper the compatibility risks and what and how 
applications/libraries depend on this behavior.


My anchor has a null PD, hidden classes share the that, so it should be 
fine (for now). (Class::getProtectionDomain returns an all permission PD 
if the class has a null PD - interesting. Looks like THAT is copied to 
the hidden class??)


I think the original security reasoning for why proxies have a null PD 
is fine goes something like this:
1. The code in the proxy is trusted, aside from  it will only 
ever calls InvocationHandler.invoke.
2. The proxy itself should not contribute to the protection domains on 
the stack - as it may sit between two privileged PDs.


The only sensible solution to keep 2. without a null PD is to use the PD 
of the invocation handler - even if that PD is null.
I'm not sure I like the idea of having a class with null PD in a package 
full of untrusted code, but that is already the case with a non-public 
interface.
An other option is to use the PD of the caller - which gets *really* 
interesting with serialization (Who is the caller now?).




That's all the feedbacks I can share so far.  We need to have a clear 
idea w.r.t. serialization spec and compatibility risk to existing code 
w.r.t. protection domain and explore other options.


Compatibility risk is always hard to assess. But I don't think that 
there is any change necessary for the serialization spec.


Otherwise - as only one new tests did fail - I would consider the risk 
low. And the failing test was in jshell, which expected a stack frame 
element from the proxy class. So, somewhat expected to break that.




W.r.t. AOT tests, AOT has been disabled in openjdk build [1] and that 
may be the reason why these tests fail.


Thanks for the info. For now, I just ignore the failures.



Mandy
[1] https://github.com/openjdk/jdk/pull/960

On 12/17/20 2:07 PM, Johannes Kuhn wrote:
Now that class data support for hidden classes in master, I decided to 
tackle JDK-8229959 again.


JDK-8229959: Convert proxy class to use constant dynamic [1]
JDK-8242888: Convert dynamic proxy to hidden classes [2]

The idea is simple: Define proxies as hidden classes, pass the methods 
as class data, and access it from the Proxy with the 
MethodHandles.classDataAt() BSM.


The current prototype[3] works - and aside from one test for jshell 
that expects a stack

JDK-8229959/JDK-8242888 Prototype for j.l.r.Proxy with hidden classes & class data

2020-12-17 Thread Johannes Kuhn
Now that class data support for hidden classes in master, I decided to 
tackle JDK-8229959 again.


JDK-8229959: Convert proxy class to use constant dynamic [1]
JDK-8242888: Convert dynamic proxy to hidden classes [2]

The idea is simple: Define proxies as hidden classes, pass the methods 
as class data, and access it from the Proxy with the 
MethodHandles.classDataAt() BSM.


The current prototype[3] works - and aside from one test for jshell that 
expects a stack trace element containing "jdk.proxy" as a stack trace 
element (hidden classes, duh), no new tests did fail with "make test-tier1".
Also, the aot tests fail ("link.exe not found"), if someone has some 
instructions how to get them properly run on windows, I'm very 
interested. But they are not new failures.


Problems I did run into:

I need a lookup for a class in a package to define a hidden class.
---
Solution: I inject an anchor class, obtain a lookup on it, and use that. 
The anchor is reused for the same package, and named pkg + ".$ProxyAnchor".


I need to return both the class data & created bytecode back to Proxy 
from ProxyGenerator

---
Solution: Added a record-like class that contains both bytecode as well 
as the class data.


Serialization of proxies did break.
---
Serializing the proxy descriptor was not a problem - the problem is how 
the constructor for serialization works.
It spins a MagicConstructorAccessor subclass - which requires for the 
created class to have a binary name. Hidden classes don't have one.
Solution: MethodHandles don't have this limitation, so I hacked a shared 
secret into JavaLangInvokeAccess to create such a MethodHandle,
and replaced the Reflection.generateConstructor() implementation to use 
a ConstructorAccessor that delegates to that MethodHandle.


---

In all, this is a prototype - for now, I want some feedback on the 
approach. Also a broader view - making it work is one thing.

Checking all the right boxes in all the different areas an other.
Some parts might still be a bit sloppy, but I want to know if there is 
merit if I follow the current path and polish it up.


- Johannes

PS.: I decided to use a draft PR - as with my last approaches I had 
problems when I did commit more stuff.


[1]: https://bugs.openjdk.java.net/browse/JDK-8229959
[2]: https://bugs.openjdk.java.net/browse/JDK-8242888
[3]: https://github.com/openjdk/jdk/pull/1830/files



Re: A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

2020-12-09 Thread Johannes Kuhn

On 09-Dec-20 19:44, Mandy Chung wrote:



On 12/8/20 6:02 PM, Johannes Kuhn wrote:

There are a lot of things to consider when trying to fix JDK-8013527.


Exactly in particular security implication!  What is clear is that the 
expected lookup class should not be the injected class.   The key 
message here is that we can't fix JDK-8257874 until we fix JDK-8013527 
unfortunately.


Mandy


Yeah, if JDK-8013527 is fixed it might fix JDK-8257874 as a byproduct.
If Lookup.lookup() can determine the original caller, then 
Field.set*/Method.invoke could do the same.
Special care has to be taken that no other class could spoof such an 
injected invoker.


Too complicated for me :). JDK-8013527 needs a sound design to approach 
fixing it IMHO.


- Johannes



Re: A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

2020-12-08 Thread Johannes Kuhn

On 09-Dec-20 1:16, Mandy Chung wrote:

On 12/8/20 5:07 AM, Johannes Kuhn wrote:


Not sure if I read this correctly as "please share some example of 
code that tries to do that" or "please share code that you write to 
fix that".

So I do both.



I was curious to find out what old software attempts to change static 
final fields via reflection and why they do that.   This leads to 
various unpredictable issues.   Looks like you want to get old 
software to work and have to hack their static final fields!!
Just do a quick search for "NoSuchFieldException modifiers". A lot of 
code does it, my impression is that often someone tried to be clever - 
just because they can.


Setting static final fields does not work [1]. It probably never 
really did. It usually seems to work - but there is no guarantee that 
it actually does (like undefined behavior).


Field::setXXX will throw IAE on static final fields and non-static 
fields declared on a record or hidden class too.
The example works with Java 8 and 11 - it "tricks" the JIT into constant 
folding a static final field, so the subsequent change is not reflected.


For the nestmate security consideration, the following invariants 
should already hold:
* To call a @CallerSensitive method, the Lookup needs to have full 
privilege access (Lookup.hasFullPrivilegeAccess())

-> Injected Invokers are only created for full privilege lookups.
* The injected invoker is in the same runtime package and has the 
same protection domain.
* It is already possible to obtain a Lookup for the injected invoker 
by calling MethodHandles.lookup() through a MethodHandle (yikes) [5].


I am concerned with this.  I am inclined to say we need to fix 
JDK-8013527 if we fix this issue.




This means, we only have to consider what additional privileges the 
injected invoker gets if it is also a nestmate of the lookup class.
I don't see any problem with that, as you already have a full 
privilege lookup when the injected invoker is created.


- Johannes

PS.: JDK-8013527 is mildly related - as the @CallerSensitive methods 
in java.lang.reflect are "hyper-sensitive".


This fix will get JDK-8013527 passed the IAE but the lookup class of 
the resulting Lookup object is the hidden class which is still incorrect.


Mandy
A quick history about JDK-8013527 (and JDK-8207834 - which has the same 
root cause, but I wrote an comment on that):


In Java 8, the injected invoker class had a name starting with 
"java.lang.invoke.". Creating a lookup for a class that starts with that 
name or binding the caller for such a class is explicitly blocked.


In Java 9 the name of the injected invoker has changed - from this point 
on, the name of the injected invoker did depend on the package of the 
lookup class / caller.
**It is already possible** to obtain a Lookup for the injected invoker 
by calling MethodHandles.lookup() through a MethodHandle.

It doesn't throw an IAE anymore. **Since Java 9.**

There are a lot of things to consider when trying to fix JDK-8013527.
The first problem is: How do you determine the original class?
It doesn't work with just using the nest host - as this might be 
different from the original class.
Using the name might also not work - as the original class could be a 
hidden class itself.


So, the only real solution is to attach that information (a reference to 
the lookup class) to the injected invoker.
Then we have to detect that the target class is an injected invoker - 
and replace it with the actual lookup class.


And this comes with some cost - either the job is done by 
Reflection.getCallerClass() - which would fix any other problem of that 
kind - or any hyper-sensitive @CallerSensitive method has to do this on 
it's own. (Luckily there are only a handful @CallerSensitive methods - 
and only a few are hyper-sensitive.)


Unfortunately, I don't know enough about hotspot to determine if it is 
possible to change the "owner class" of some code. Also, garbage 
collection...
I don't know enough about those systems. I only look at the stuff from 
the Java / bytecode side.


In the end, I'm not sure if fixing l.lookupClass() == ((Lookup) 
l.findStatic(MethodHandles.class, "lookup", 
MethodType.methodType(Lookup.class)).invokeExact()).lookupClass() is 
worth that effort.


- Johannes



Re: A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

2020-12-08 Thread Johannes Kuhn

On 08-Dec-20 5:40, Mandy Chung wrote:

Thanks David.  I was about to create one.

This is indeed a gap in injecting this trampoline class for supporting 
@CallerSensitive methods.  The InjectedInvoker ensures that the 
InjectedInvoker class has the same class loader as the lookup class.  
W.r.t. your patch, it seems okay but I have to consider and think 
through the security implication carefully.


You mentioned "Some old software loves to set static final fields 
through reflection" - can you share some example libraries about 
this?   This is really ugly hack!!


Mandy 


Not sure if I read this correctly as "please share some example of code 
that tries to do that" or "please share code that you write to fix that".

So I do both.

Setting static final fields does not work [1]. It probably never really 
did. It usually seems to work - but there is no guarantee that it 
actually does (like undefined behavior).


JPEXS [2] for example used that for it's configuration.
Also some old Minecraft Forge version (a Minecraft mod loader / mod API) 
depends on this. Example use [3], but they do really ugly things.


So, I said I develop agents to get old stuff running on a current Java 
version.
Why? Fun, I guess. I also learn a lot a about what are the main 
comparability problems with newer Java versions.

Pros of writing an agent:
* I don't need the source code.
* I don't need to setup a build environment with all dependencies, 
lombok and who knows what else is required.
In all, it's faster for me. And I then have a list of problems - and how 
they can be solved. I did publish my JPESX agent here [4].

But yeah, it's an ugly hack.

For the nestmate security consideration, the following invariants should 
already hold:
* To call a @CallerSensitive method, the Lookup needs to have full 
privilege access (Lookup.hasFullPrivilegeAccess())

-> Injected Invokers are only created for full privilege lookups.
* The injected invoker is in the same runtime package and has the same 
protection domain.
* It is already possible to obtain a Lookup for the injected invoker by 
calling MethodHandles.lookup() through a MethodHandle (yikes) [5].


This means, we only have to consider what additional privileges the 
injected invoker gets if it is also a nestmate of the lookup class.
I don't see any problem with that, as you already have a full privilege 
lookup when the injected invoker is created.


- Johannes

PS.: JDK-8013527 is mildly related - as the @CallerSensitive methods in 
java.lang.reflect are "hyper-sensitive".


[1]: https://gist.github.com/DasBrain/25c6738610c517ee375aacc86ffebd0c
[2]: 
https://github.com/akx/jpexs-decompiler/blob/6c998254b9d5bdce80be1b92d34836820ee31a1d/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java#L869
[3]: 
https://github.com/Chisel-Team/Chisel/blob/1.12/dev/src/main/java/team/chisel/common/init/ChiselBlocks.java#L18
[4]: 
https://github.com/DasBrain/jpex/tree/master/src/pw/dasbrain/jpexs/agent

[5]: https://gist.github.com/DasBrain/142cb8ef9cc16e7469ac519790119e07



A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

2020-12-07 Thread Johannes Kuhn

Let's start with the reproducer:

    public class NestmateBug {
    private static int field = 0;
    public static void main(String[] args) throws Throwable {
    Lookup l = MethodHandles.lookup();
    Field f = NestmateBug.class.getDeclaredField("field");
    MethodHandle mh = l.findVirtual(Field.class, "setInt", 
methodType(void.class, Object.class, int.class));

    int newValue = 5;
    mh.invokeExact(f, (Object) null, newValue);
    }
    }

This throws a IAE in the last line:

class test.se15.NestmateBug$$InjectedInvoker/0x000800bb5840 (in 
module test.se15) cannot access a member of class test.se15.NestmateBug 
(in module test.se15) with modifiers "private static"
    at 
java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:385)
    at 
java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:693)

    at java.base/java.lang.reflect.Field.checkAccess(Field.java:1096)
    at java.base/java.lang.reflect.Field.setInt(Field.java:976)
    at test.se15/test.se15.NestmateBug.main(NestmateBug.java:17)

The reason for this behaviour is:
* Field.setInt (without setAccessible) requires that the caller class is 
in the same nest for private members.

* Field.setInt is @CallerSensitive
* MethodHandles will bind to the caller by injecting an invoker for 
@CallerSensitive methods.

* The injected invoker is NOT a nestmate of the original lookup class.
* The access check of Field.setInt fails - as the injected invoker is 
now the caller.


This is important because:
* Some old software loves to set static final fields through reflection.
* To do that, it usually hacks into Field.modifiers. Which is filtered 
iirc since Java 12.
* I write Java agents to fix such things - removing final from static 
fields, and intercept Class.getDeclaredField and Field.setInt by 
replacing it with an invokedynamic instruction.
* The original target is passed as a MethodHandle bootstrap argument. In 
the case of Field.setInt, it is guarded with a 
MethodHandles.guardWithTest() - calling the original target if the Field 
is not my canary.


Suggested fix:
* Make the injected invoker a nestmate of lookup class.

I did prepare a fix for that [1], but AFAIK the bug first needs to be 
filled in the bug tracker.

And I don't have an account.

- Johannes


[1]: 
https://github.com/DasBrain/jdk/commit/3c4bb20c8e4cd9086e934128e5cb085a5cfbdb94




Can sun.misc.Unsafe.throwException() be removed?

2020-08-04 Thread Johannes Kuhn
From my understanding, Unsafe.throwException throws the passed 
Throwable, more commonly known as "snaky throws".


There are other ways to archive the same result, one commonly found is 
by (ab)using generics:


    public static  void sneakyThrows(Throwable t) 
throws T {

    throw (T) t;
    }

(This will generate an unchecked warning, but that can be silenced with 
the right annotation.)


Is there any reason why this method still needs to exist?
If not, could it be removed?

- Johannes



Re: RFR: 8247532: Records deserialization is slow

2020-06-14 Thread Johannes Kuhn

On 14-Jun-20 18:28, Peter Levart wrote:

Hi,


I noticed that deserializing records (new preview Java feature in 
JDK14 and JDK15) is slow compared to equivalent classical classes. I 
created a JMH benchmark [1] to se how it compares (ran it on JDK14):



Benchmark Mode  Cnt   Score    Error   Units
RecordSerializationBench.deserializeClasses avgt   10  31.911 
±  0.218   us/op
RecordSerializationBench.deserializeClasses:·gc.alloc.rate avgt   
10 815.106 ±  5.545  MB/sec
RecordSerializationBench.deserializeClasses:·gc.alloc.rate.norm avgt   
10   40921.903 ±  0.615    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space 
avgt   10 839.522 ±    191.195  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space.norm 
avgt   10   42153.661 ±   9682.799    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space 
avgt   10   0.117 ±  0.492  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space.norm 
avgt   10   5.835 ± 24.447    B/op
RecordSerializationBench.deserializeClasses:·gc.count avgt   10  
21.000   counts
RecordSerializationBench.deserializeClasses:·gc.time avgt   10  
17.000   ms
RecordSerializationBench.deserializeRecords avgt   10 531.333 
±  3.094   us/op
RecordSerializationBench.deserializeRecords:·gc.alloc.rate avgt   
10 346.511 ±  1.997  MB/sec
RecordSerializationBench.deserializeRecords:·gc.alloc.rate.norm avgt   
10  289637.193 ±  6.894    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space 
avgt   10 359.773 ±    191.116  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space.norm 
avgt   10  300657.838 ± 159724.346    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space 
avgt   10   0.007 ±  0.012  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space.norm 
avgt   10   6.020 ±  9.910    B/op
RecordSerializationBench.deserializeRecords:·gc.count avgt   10   
9.000   counts
RecordSerializationBench.deserializeRecords:·gc.time avgt   10  
14.000   ms



...not only it is it about 16x slower, it also produces 7x garbage. I 
checked the code and it is not very optimal. It matches the record 
component names with object stream fields in O(n^2) way. It uses 
method handles but binds arguments of canonical constructor each time 
an instance of record is constructed. So I tried to optimize it [2] 
and with that patch on top of JDK16 the benchmark produces the 
following results:



Benchmark Mode  Cnt  Score   Error   Units
RecordSerializationBench.deserializeClasses avgt   10 31.049 ± 
0.235   us/op
RecordSerializationBench.deserializeClasses:·gc.alloc.rate avgt   
10    837.614 ± 6.326  MB/sec
RecordSerializationBench.deserializeClasses:·gc.alloc.rate.norm avgt   
10  40921.931 ± 0.666    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space 
avgt   10    867.743 ±   251.373  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space.norm 
avgt   10  42405.532 ± 12403.301    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space 
avgt   10  0.126 ± 0.478  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space.norm 
avgt   10  6.113 ±    23.268    B/op
RecordSerializationBench.deserializeClasses:·gc.count avgt   10 
22.000  counts
RecordSerializationBench.deserializeClasses:·gc.time avgt   10 
19.000  ms
RecordSerializationBench.deserializeRecords avgt   10 33.588 ± 
0.394   us/op
RecordSerializationBench.deserializeRecords:·gc.alloc.rate avgt   
10    500.033 ± 5.871  MB/sec
RecordSerializationBench.deserializeRecords:·gc.alloc.rate.norm avgt   
10  26425.293 ± 0.759    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space 
avgt   10    512.772 ±   288.112  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space.norm 
avgt   10  27090.499 ± 15175.280    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space 
avgt   10  0.134 ± 0.496  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space.norm 
avgt   10  7.128 ±    26.526    B/op
RecordSerializationBench.deserializeRecords:·gc.count avgt   10 
13.000  counts
RecordSerializationBench.deserializeRecords:·gc.time avgt   10 
17.000  ms



...so here the speed is comparable and it even produces less garbage.


I created an issue [3].

So WDYT? Since this is still a preview feature in JDK15, is it 
possible to squeeze it into JDK15?


Regards, Peter


[1] 
http://cr.openjdk.java.net/~plevart/jdk-dev/RecordsDeserialization/RecordSerializationBench.java


[2] 

Re: JPackage with a modular application fails to load record class files even with --enable-preview

2020-06-09 Thread Johannes Kuhn
Relevant StackOverlow question: 
https://stackoverflow.com/questions/61504956/records-in-jlinked-application-throws-exception


It talks about JLink, but the error message is the same, so I expect the 
same root cause:
The ASM version shipped with JDK 14 doesn't support records yet. It is 
already fixed for JDK 15.


- Johannes

On 09-Jun-20 16:40, Andy Herrick wrote:
So when you use the jpackage option "--java-options --enable-preview" 
it appears to work with a non-modular jar, but not with a modular jar ?


I think I can create a testcase for that.

Have you tried it with the jpackage from a preview release of JDK15  
(https://jdk.java.net/15/) ?


Can you look at the runtime in the app-image of the failing case, and 
see if the preview module is there ?  Perhaps the problem is the way 
jpackage invokes jlink.


A final thing you can try is run jlink yourself, and use the resulting 
runtime-image in jpackage args.


/Andy

On 6/7/2020 9:07 AM, Markus Jevring wrote:
I have this app, which uses Java 14 with –enable-preview and records. 
If I turn it in to a normal non-modular jar, it works with both java 
-jar –enable-preview myapp.jar, and with a native image built with 
jpackage. However, when i turn it into a modular jar, I can still 
launch it with java –enable-preview –module-path ... –module ..., 
but  when I try to create a native image using jpackage usign the 
same modular flags, launching it fails. I get a dialog box saying 
“Failed to launch JVM”, and if I enable –win-console when I build it 
and relaunch it, it tells me this:


Exception in thread "main" java.lang.ClassFormatError: Invalid 
constant pool index 31 for name in Record attribute in class file 
net/jevring/frequencies/v2/input/KeyTimings$Note

 at java.base/java.lang.ClassLoader.defineClass2(Native Method)
 at java.base/java.lang.ClassLoader.defineClass(Unknown Source)
 at 
java.base/java.security.SecureClassLoader.defineClass(Unknown Source)
 at 
java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(Unknown 
Source)
 at 
java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(Unknown 
Source)
 at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(Unknown 
Source)
 at 
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown 
Source)
 at 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown 
Source)

 at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
 at 
frequencies/net.jevring.frequencies.v2.input.KeyTimings.(Unknown 
Source)
 at 
frequencies/net.jevring.frequencies.v2.Thief.(Unknown Source)
 at frequencies/net.jevring.frequencies.v2.Main.main(Unknown 
Source)


Note, above, is a record. I tried moving it out to a separate class, 
and I still got the same error. When I converted Note to a normal 
class, it started complaining about the next record it cound.
I know that it’s picking up the –enable-preview java option, because 
when I omit that, it complains about the class file version being wrong.


Since I can run it just fine using “java -jar”, and it works fine 
under all other circumstances, I must conclude that there’s something 
wrong with the intersection of modular jars and jpackage.
I’ve googled around plenty, and I haven’t found anything that might 
help me. I’m not sure if this is a call for help or a bug report, 
though I’d like to consider it the latter =)


I put what I had on a branch: 
https://bitbucket.org/jevring/frequencies/branch/java-modules
I realize it’s not a small self-contained example that replicates the 
issue, and for that I’m sorry. If someone is interested about this, I 
could try to make one.





JDK-8229959: Current status and thoughts about JDK-8242888

2020-06-03 Thread Johannes Kuhn

Hi,

half a year ago, I proposed a patch that implements JDK-8229959: Convert 
proxy class to use constant dynamic [2].


**Background**: java.lang.reflect.Proxy creates a class file at runtime 
that extends j.l.r.Proxy and implements the passed interfaces.
Methods invoked on that proxy are passed to a 
j.l.r.InvocationHandler.invoke. One of it's argument is a j.l.r.Method.
This Method is currently cached in a private static final field in the 
generated proxy class.

Remi Forax suggested to use a constant dynamic instead.

Last time I was not sure about the scope of my proposal, and when 
discussion drifted to related topics, I did not know how to handle that.
After some thought, the scope of this is only changing the shape of the 
generated class file. Those are NOT in the scope:


* Changes to a public API.
* Changes on how the generated class file is loaded.

Especially JDK-8242888: Convert dynamic proxy to hidden classes [3] is 
not in scope. But see below for some thoughts on it.


-

To avoid changing the specification, I decided to put the bootstrap 
method for the constant dynamic into the generated class file.

My first approach was a bootstrap method that is equivalent to this:

    private static Method $proxy$bootstrap(Lookup l, String ignored, 
Class jlrMethod, MethodHandle mh) {

    return (Method) lookup.revealDirect(mh).reflectAs(jlrMethod);
    }

One of the responses was to measure the impact, and I wrote some JMH 
tests - which did run that code JITed.
It is much more likely that this code is executed in the interpreter 
through.


Brian Goetz then suggested to write a bootstrap method per proxy mehod, 
and calling Class::getMethod in them.
After some tries, I found a way to parameterize it, using MethodType as 
carrier.

This avoids encoding the primitive types as yet an other constant dynamic.
Example bootstrap method:

    private static Method $proxy$bootstrap(Lookup l, String name, Class 
jlrMethod, Class owner, MethodType mt) {

    return owner.getMethod(name, mt.parameterArray());
    }


This approach seemed to work - until I did look into the interaction 
with an installed SecurityManager.


Class::getMethod can throw a SecurityException if the method belongs to 
an interface that is in a package not exported by the JDK.
In particular, it breaks j.l.i.MethodHandleProxies.wrapperInstanceTarget 
when a SecurityManager is installed. [4]
(A separate change could be made to fix that particular case, but I 
consider it just to be a symptom.)


This breaks because Class::getMethod is called at a later point - when 
untrusted code is on the stack.


--

Where can this go from here?

* Wrap the call to Class::getMethod in an AccessController.doPrivileged 
block.

  While possible, this would add even more overhead.
* Go back to revealDirect/reflectAs.
  This does not work because Lookup::revealDirect will check the 
package access.

* Use hidden classes, as suggested by JDK-8242888.
  A promising approach, but has a few unsolved problems.

What about hidden classes?
It's possible to pass some ClassData to a hidden class when defining it.
Which can be used to pass the Methods.

But Hidden Classes need some more requirements, as outlined by Mandy in 
JDK-8242888:


* Serialization: No change necessary.
  Proxy classes (as determined by Proxy.isProxyClass) are written as a 
proxy descriptor, containing a list of all implemented interfaces.
  Deserialization is fine if Proxy.h can be updated even if the 
instance is implemented by a hidden class.

* A lookup in the same package as the proxy is needed.
  This is a problem for not-yet-existing packages. It's possible to 
inject a "package-witness" or shim.

* Protection domain: Proxy is defined to have a null ProtectionDomain.
  This is currently necessary for Class.getMethod.
  If the methods are passed using ClassData, then that requirement is 
no longer needed.

  An other option is to grant the package witness a null ProtectionDomain.

As conclusion, JDK-8229959 can only be implemented if it either uses 
AccessController.doPrivileged or use hidden classes with ClassData.


- Johannes

[1]: https://bugs.openjdk.java.net/browse/JDK-8229959
[2]: 
https://mail.openjdk.java.net/pipermail/core-libs-dev/2019-November/063595.html

[3]: https://bugs.openjdk.java.net/browse/JDK-8242888
[4]: https://gist.github.com/DasBrain/37855876743fed7828c7690603aa3039



Re: RFR: JDK-8245432: Lookup::defineHiddenClass should throw UnsupportedClassVersionError if the given bytes are of an unsupported major or minor version

2020-05-29 Thread Johannes Kuhn

Thanks.

Noted that readInt can read outside of the byte array when it is shorter 
than 4 bytes, throwing an ArrayIndexOutOfBoundsException.

Same applies for readUnsignedShort.

Test cases for malformedClassFiles:

new byte[3], new byte[] {0xCA, 0xFE, 0xBA, 0xBE, 0x00}


- Johannes


On 29-May-20 21:23, Mandy Chung wrote:

It's fixed.  Thanks
Mandy

On 5/28/20 4:35 PM, Johannes Kuhn wrote:

Hi,

just noticed a small thing:
The magic is 4 bytes, but readUnsignedShort reads two bytes.

- Johannes

On 28-May-20 19:25, Mandy Chung wrote:



On 5/28/20 6:55 AM, Alan Bateman wrote:

On 28/05/2020 05:13, Mandy Chung wrote:

Updated webrev:
http://cr.openjdk.java.net/~mchung/jdk15/webrevs/8245432/webrev.01/

I modify this patch to check the class file version and throws CFE 
if unsupported before creating ClassReader. This also fixes 
JDK-8245061 that it reads the value of `this_class` as a constant 
(as ASM will throw an exception if it's not a constant) and also 
ensures that `this_class` is a CONSTANT_Class_info by checking the 
descriptor string from Type.
I don't want to complicate this further but the --enable-preview 
handling in the VM doesn't seem to expose an internal property that 
allows code in the libraries know if preview feature are enabled or 
not. I was assuming that isSupportedClassFileVersion would need to 
check that.




The runtime will ensure if --enable-preview is set if a class file 
with minor is loaded.   I will prefer to keep 
VM::isSupportedClassFileVersion to validate the given major/minor 
version.  At runtime, it will fail when such class file is loaded if 
preview is not enabled.


I'll add a comment to describe that.

Will readUnsignedShort throw AIOBE if the offset is beyond the length? 


Good catch.  I add the check to throw CFE.
+    private static int readUnsignedShort(byte[] bytes, int 
offset) {

+    if (offset >= bytes.length) {
+    throw new ClassFormatError("Invalid ClassFile 
structure");

+    }
+    return ((bytes[offset] & 0xFF) << 8) | 
(bytes[offset + 1] & 0xFF);

+    }

Also are you sure about "& 0xCAFEBABE", I assumed it would just 
check the magic number is equal to that.


It should check ==.  Fixed.

thanks
Mandy









Re: RFR: JDK-8245432: Lookup::defineHiddenClass should throw UnsupportedClassVersionError if the given bytes are of an unsupported major or minor version

2020-05-28 Thread Johannes Kuhn

Hi,

just noticed a small thing:
The magic is 4 bytes, but readUnsignedShort reads two bytes.

- Johannes

On 28-May-20 19:25, Mandy Chung wrote:



On 5/28/20 6:55 AM, Alan Bateman wrote:

On 28/05/2020 05:13, Mandy Chung wrote:

Updated webrev:
http://cr.openjdk.java.net/~mchung/jdk15/webrevs/8245432/webrev.01/

I modify this patch to check the class file version and throws CFE 
if unsupported before creating ClassReader.  This also fixes 
JDK-8245061 that it reads the value of `this_class` as a constant 
(as ASM will throw an exception if it's not a constant) and also 
ensures that `this_class` is a CONSTANT_Class_info by checking the 
descriptor string from Type.
I don't want to complicate this further but the --enable-preview 
handling in the VM doesn't seem to expose an internal property that 
allows code in the libraries know if preview feature are enabled or 
not. I was assuming that isSupportedClassFileVersion would need to 
check that.




The runtime will ensure if --enable-preview is set if a class file 
with minor is loaded.   I will prefer to keep 
VM::isSupportedClassFileVersion to validate the given major/minor 
version.  At runtime, it will fail when such class file is loaded if 
preview is not enabled.


I'll add a comment to describe that.

Will readUnsignedShort throw AIOBE if the offset is beyond the length? 


Good catch.  I add the check to throw CFE.
+    private static int readUnsignedShort(byte[] bytes, int 
offset) {

+    if (offset >= bytes.length) {
+    throw new ClassFormatError("Invalid ClassFile 
structure");

+    }
+    return ((bytes[offset] & 0xFF) << 8) | (bytes[offset 
+ 1] & 0xFF);

+    }

Also are you sure about "& 0xCAFEBABE", I assumed it would just check 
the magic number is equal to that.


It should check ==.  Fixed.

thanks
Mandy





Mismatch between spec and implementation of DataInputStream.readFully(byte[], int, int)

2020-05-14 Thread Johannes Kuhn
Found a small mismatch between the specification of 
DataInputStream.readFully(byte[] b, int off, int len) and its 
implementation.


In particular, it doesn't throw an IndexOutOfBoundsException if offset 
is negative and len is 0.


Reproducer below.

I suggest changing the specification of this method to allow that behavior.
This change should also affect DataInput, where care has to be taken 
that both behaviors are legal.


- Johannes

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;

public class DISBug {
    public static void main(String[] args) throws IOException {
    try (var bais = new ByteArrayInputStream(new byte[0]);
    var dis = new DataInputStream(bais)) {
    // From the spec:
    // throws IndexOutOfBoundsException - if off is negative, 
len is negative, or len is greater than b.length - off.

    byte[] b = new byte[0];
    int off = -1; // This is not valid
    int len = 0;
    dis.readFully(b, off, len);
    throw new AssertionError("readFully did not throw");
    } catch (IndexOutOfBoundsException expected) {
    // Ignore, this exception is expected
    }
    }
}



Re: JDK-8226810: An other case and a small change suggestion

2020-05-11 Thread Johannes Kuhn

On 11-May-20 10:59, Alan Bateman wrote:



On 10/05/2020 15:47, Johannes Kuhn wrote:

:

After the discussion with Naoto, I would like to change the one line 
to strcpy(ret + 2, "1252")


diff --git a/src/java.base/windows/native/libjava/java_props_md.c 
b/src/java.base/windows/native/libjava/java_props_md.c

--- a/src/java.base/windows/native/libjava/java_props_md.c
+++ b/src/java.base/windows/native/libjava/java_props_md.c
@@ -73,6 +73,7 @@
   LOCALE_IDEFAULTANSICODEPAGE,
   ret+2, 14) == 0) {
 codepage = 1252;
+    strcpy(ret + 2, "1252");
 } else {
 codepage = atoi(ret+2);
 }

I have already signed the OCA.
This would be my first patch. Is there anything else you need?

I will take a further look into GetLocaleInfo, and try to find a 
model that works for me (currently thinking about blackbox, can 
return anything from [1]),

and then discussing how to handle all those cases.
It's not clear how conditions are necessary for GetLocaleInfo to fail 
but good to fix this code path. We should probably create a new issue 
in JIRA for this as it's not clear that it is the same issue as 
JDK-8226810. We've been chasing JDK-8226810 for some time but have not 
been able to find a system where it duplicates. The reports so far 
suggests is Windows Chinese but most of the people that report the 
issue to not respond to questions so we can't be sure. One of the 
reports (see my comment in the bug from June 2019) suggests the code 
page is 54936, useful information as GB18030 is not in java.base. Once 
your fix is in then I think we should try to improve the exception 
message rather than NPE. There may be some of these cases where it 
should default to UTF-8.


-Alan.


I agree.
Looking through the JDK code, the IMHO best way to create a hook for 
this is Charset.defaultCharset().
Instead of using GetPropertyAction, it could retrieve 
System.getProperties and do a null check there. This has probably the 
least impact on performance as this code path is only executed once.
Indeed, it could (theoretically) emit a warning/debug message there with 
debug information and return sun.nio.cs.UTF_8.INSTANCE as fallback 
without setting defaultCharset.


But that is a hard problem. I don't really like adding a warning to java 
startup, even if it would not work before just to get debug information.
On the other hand, just continuing as if nothing did happen could hide 
further bugs. (Also, how would I get the debug info from the Java side, 
as properties are not yet initialized.)


I wrote a small C program which just outputs the result of 
GetLocaleInfo(GetSystemDefaultLCID(), LOCALE_IDEFAULTANSICODEPAGE, ...).

I was not able to influence that result - on my machine it's always 1252.

My current understanding of codepages is basically: They are like encodings.
They come in two variants (?): ANSI and non-ANSI. The ansi codepages use 
ANSI for bytes between 0 and 127.
Each system, application or thread (wtf? see CP_THREAD_ACP) can have a 
different current codepage.
Some windows API functions (the *A variants) use the current codepage 
(as returned by GetACP) to translate the string from/to unicode.
GetACP returns the codepage identifier for the operating system. (No 
mention of thread in the doc for that, so why is there even CP_THREAD_ACP?)


It's a rabbit hole.
If someone knows about a way to influence the result of 
GetLocaleInfo(GetSystemDefaultLCID(), LOCALE_IDEFAULTANSICODEPAGE, ...), 
then at least reproducing the error would become possible.


- Johannes



Re: JDK-8226810: An other case and a small change suggestion

2020-05-10 Thread Johannes Kuhn

On 09-May-20 1:27, Brent Christian wrote:

On 5/7/20 5:50 AM, Alan Bateman wrote:

On 07/05/2020 12:37, Johannes Kuhn wrote:

:

In the end, I don't know what causes the bug, or how I can replicate 
it.

I think I did find a likely suspect.

>
Good sleuthing. I don't what the conditions are for GetLocaleInfo to 
fail but it does look like that would return possibly non-terminated 
garbage starting with "CP" so we should at least fix that.


I agree.  I can file a bug and sponsor this small change.

-Brent

Thank you.

After the discussion with Naoto, I would like to change the one line to 
strcpy(ret + 2, "1252")


diff --git a/src/java.base/windows/native/libjava/java_props_md.c 
b/src/java.base/windows/native/libjava/java_props_md.c

--- a/src/java.base/windows/native/libjava/java_props_md.c
+++ b/src/java.base/windows/native/libjava/java_props_md.c
@@ -73,6 +73,7 @@
   LOCALE_IDEFAULTANSICODEPAGE,
   ret+2, 14) == 0) {
 codepage = 1252;
+    strcpy(ret + 2, "1252");
 } else {
 codepage = atoi(ret+2);
 }

I have already signed the OCA.
This would be my first patch. Is there anything else you need?

I will take a further look into GetLocaleInfo, and try to find a model 
that works for me (currently thinking about blackbox, can return 
anything from [1]),

and then discussing how to handle all those cases.

- Johannes

[1]: 
https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers


Re: JDK-8226810: An other case and a small change suggestion

2020-05-08 Thread Johannes Kuhn

Thanks.

I think strcpy(ret+2, "1252") vs. strcpy(ret, "Cp1252")  is a just 
matter of style. I would prefer the later, as it makes the intent clear.

But not my call.

Do you have any info how I can change the detected codepage there? I 
wrote a small C program that basically just does that part and printf it.
In my limited tests (windows likes to require a restart after each 
configuration change) I did not find a way to influence that.


An other thing to consider is if Cp65001 should be treated as UTF-8 in 
that function?
(As said before, locale is not my expertise. Can that function with that 
LCSID even return 65001?)
I can see how things go wrong if it returns 65001 as locale, so... could 
be a safe change? (I'm sure that things break if that function returns 
65001.)


Then there is the other part:
The mismatch between the comment in jni_util.c/newSizedStringJava and 
the implementation on the Java side.
There is no fallback to iso-8859-1. If new String(byte[]) is called 
before the system properties are installed, then this will lead to a 
NullPointerException.
And there is a code path that leads to exactly that - newPlatformString 
is called from the initialization of the properties. [1]
And if the encoding returned by the windows function is not supported, 
then it will call new String(byte[]) - during system property 
initialization.


- Johannes

[1]: 
https://hg.openjdk.java.net/jdk/jdk/file/d40d865753fb/src/java.base/share/native/libjava/System.c#l207


On 08-May-20 18:27, naoto.s...@oracle.com wrote:

Ditto. Good catch!

I am not sure the fix would address the issue in 8226810 (cannot 
confirm it either, as my Windows box is at my office where I cannot 
enter at the moment :-), but this definitely looks like a bug. I would 
change the additional line to "strcpy(ret+2, "1252");" as Cp is copied 
in the following switch.


Naoto



On 5/7/20 5:50 AM, Alan Bateman wrote:

On 07/05/2020 12:37, Johannes Kuhn wrote:

:

In the end, I don't know what causes the bug, or how I can replicate 
it.

I think I did find a likely suspect.
Good sleuthing. I don't what the conditions are for GetLocaleInfo to 
fail but it does look like that would return possibly non-terminated 
garbage starting with "CP" so we should at least fix that.


The issue in JDK-8226810 might be something else. One of the 
submitters to that issue did engage and provided enough information 
to learn that the locale is zh_CN and also reported that it was 
failing for GB18030. GB18030 is not in java.base so that at least 
explained that report.


-Alan





JDK-8226810: An other case and a small change suggestion

2020-05-07 Thread Johannes Kuhn
I just saw a question on StackOverflow [1] which reports to have the 
same issue as in JDK-8226810 [2] - with the same stack trace.


While I could not reproduce the issue, I tried to understand which code 
path could lead to that outcome.

While doing so I did come across getEncodingInternal in java_props_md.c [3]

The path when GetLocaleInfo in line 72 fails just sets the codepage to 1252.
The following switch doesn't have a branch for codepage 1252, so the 
default branch is used.


The first two elements of the char array are set to "Cp", while the rest 
of that char array is still uninitialized.

This (partially) uninitialized array is then returned.

This seems wrong.
I would therefore either change codepage to 0 (resulting in a default 
encoding of UTF-8) or also copy the "Cp1252" to the char buffer.



(More when I follow this code path):
In InitializeEncoding [4] this invalid encoding is then set to 
jnuEncoding, and fastEncoding to NO_FAST_ENCODING.
A call to JNU_NewStringPlatform will then result in a call to 
newSizedStringJava [5], where jnuEncodingSupported is called.
This calls java.nio.charset.Charset.isSupported(jnuEncoding) and caches 
the result - I assume it returns false. Or throws.


This means new String(byte[]) is called.

Here comes the puzzler: java.lang.StringCoding.decode(byte[],int,int) 
calls Charset.getDefaultCharset() as first action.
- and does not fall back to iso-8859-1 as the comment in 
newSizedStringJava suggests.


Charset.getDefaultCharset() then tries to read the properties - which 
are currently in the process to be initialized - and fails with a 
NullPointerException.




In the end, I don't know what causes the bug, or how I can replicate it.
I think I did find a likely suspect.

I therefore would like to propose the following patch:

diff --git a/src/java.base/windows/native/libjava/java_props_md.c 
b/src/java.base/windows/native/libjava/java_props_md.c

--- a/src/java.base/windows/native/libjava/java_props_md.c
+++ b/src/java.base/windows/native/libjava/java_props_md.c
@@ -73,6 +73,7 @@
   LOCALE_IDEFAULTANSICODEPAGE,
   ret+2, 14) == 0) {
 codepage = 1252;
+    strcpy(ret, "Cp1252");
 } else {
 codepage = atoi(ret+2);
 }

Because this path is not taken on my system, I can't test if this change 
affects anything. Tests run as before.

But I still think that it is The Right Thing To Do.

Maybe logging the GetLastError too - but it's very early in the VM's 
startup.
I did consider calling GetLocaleInfo twice - with NULL as buffer and 0 
as length - which returns the required size of the buffer.

But that would have some implication on the startup time.
I could also check GetLastError and try again with a bigger buffer - but 
then the question arises: Can the VM handle such a charset?


Johannes

[1]: 
https://stackoverflow.com/questions/61650372/jdk-14-0-1-error-occurred-during-initialization-of-vm-java-lang-nullpointerexcep

[2]: https://bugs.openjdk.java.net/browse/JDK-8226810
[3]: 
https://hg.openjdk.java.net/jdk/jdk/file/d40d865753fb/src/java.base/windows/native/libjava/java_props_md.c#l64
[4]: 
https://hg.openjdk.java.net/jdk/jdk/file/d40d865753fb/src/java.base/share/native/libjava/jni_util.c#l773
[5]: 
https://hg.openjdk.java.net/jdk/jdk/file/d40d865753fb/src/java.base/share/native/libjava/jni_util.c#l661




Re: Some Classes with a public void close() don't implement AutoCloseable

2020-04-16 Thread Johannes Kuhn

updated the code, similar output. Disregard org/w3c/dom/html/HTMLDocument
https://gist.github.com/DasBrain/df25a69acf564dcb5f2241cc065be2ed

About java.xml.stream: A XMLStreamReader is for example constructed with:

    BufferedReader br = ...;
    XMLStreamReader xsr = 
XMLInputFactory.newDefaultFactory().createXMLEventReader(br);


For my IDE this would look like XMLStreamReader wraps the 
BufferedReader, so it won't issue a warning if I don't close br.

But the Javadoc for XMLStreamReader.close() states:

> Frees any resources associated with this Reader. This method does not 
close the underlying input source.


If those classes would implement AutoCloseable, people and IDEs might 
wrongly assume that it would close the BufferedReader.

Which would result in code like this:

    try (var xsr = 
XMLInputFactory.newDefaultFactory().createXMLEventReader(Files.newBufferedReader(path, 
StandardCharsets.UTF_8))) {  ... }


And have a resource leak. Incidentally, that is the similar to the code 
I tried to write when I saw that XMLStreamReader has a public void 
close() method.
So in my opinion, to let XMLStreamReader implement AutoCloseable, the 
specification of the close() method should be changed.


The same applies for the other XML Stream/Event Reader/Writer.

Thanks,
Johannes

On 16-Apr-20 9:28, Alan Bateman wrote:

On 16/04/2020 01:28, Johannes Kuhn wrote:

:

I did not restrict my enumeration to public and exported types - it 
was easier not to do that and I'm lazy.
Most of the candidates that you've identified are JDK internal classes 
and there are several non-public classes in exported packages. There 
are also a few cases where the sub-classes of the likely candidate are 
showing up too (e.g. all the public sub-classes of 
java.util.logging.Handler). I skimmed through your list and filtered 
it down to the public classes in exported packages to following:


com/sun/jdi/connect/spi/Connection
java/awt/SplashScreen
java/util/logging/Handler
javax/naming/Context
javax/naming/NamingEnumeration
javax/naming/ldap/StartTlsResponse
javax/smartcardio/CardChannel
javax/sql/PooledConnection
javax/swing/ProgressMonitor
javax/xml/stream/XMLEventReader
javax/xml/stream/XMLEventWriter
javax/xml/stream/XMLStreamReader
javax/xml/stream/XMLStreamWriter

As Joe points out, some of these may have been looked at already. I 
was surprised to see the java.xml.stream reader/writers so it might be 
worth digging into those to see why they were not retrofitted.


-Alan.







Re: Some Classes with a public void close() don't implement AutoCloseable

2020-04-15 Thread Johannes Kuhn

Hi Joe,

thanks for all the info.
As I'm not yet familiar with the way how OpenJDK is developed, mind if I 
ask what steps would have to be taken to add Closeable to 
javax.naming.Context?

The first thing would be to create a patch, test it, run the tests.
Then the change has to be proposed, and reviewed. You can argue that 
this might waste the time of the reviewers with such a small patch.

Is there something else that would need to be done?

I have read http://openjdk.java.net/contribute/ and signed the OCA, but 
on the other hand, it's such a small change that most already know how 
the patch will look.
I am not even sure if my time would be spend wisely. The motivation 
would be to do it to learn how to contribute.


Anyway, thank you for your time and consideration. This just some stuff 
I found, then wrote some code, got some results and did not know what I 
can or should do with that.


Thanks,
Johannes

On 16-Apr-20 3:15, Joe Darcy wrote:

Hi Johannes,

FYI, back during Project Coin during JDK 7, there were various 
systematic efforts to review types with a "close" method in the JDK 
and retrofit AutoCloseable where appropriate:


    JDK-6911261: Project Coin: Retrofit Automatic Resource Management 
(ARM) support onto platform APIs

    https://bugs.openjdk.java.net/browse/JDK-6911261

    JDK-6963723: Project Coin: Retrofit more JDK classes for ARM
    https://bugs.openjdk.java.net/browse/JDK-6963723

If you'll excuse the bad import into another blogging system, the 
process of finding the candidate types with an annotation processor 
and doing the retrofitting was discussed in a blog entry from that time:


https://blogs.oracle.com/darcy/project-coin:-bringing-it-to-a-closeable


More recently fixed in JDK 14,

    JDK-8203036: com.sun.net.httpserver.HttpExchange should implement 
AutoCloseable

    https://bugs.openjdk.java.net/browse/JDK-8203036

and as of August 2019, closed as will not fix given lack of interest:

    JDK-7057061: Support autocloseable for javax.naming.Context
    https://bugs.openjdk.java.net/browse/JDK-7057061

Thanks,

-Joe

On 4/15/2020 5:28 PM, Johannes Kuhn wrote:
After failing to wrap a XMLStreamReader in a try-with-resources after 
discovering it's close() method,
I thought about checking what other classes have a public void 
close() method in the JDK but don't implement AutoCloseable.


So I wrote a small program that enumerates all classes present in in 
the jrt image with a public void close() method that does not

directly or indirectly implement AutoCloseable:
https://gist.github.com/DasBrain/8d50e02e35654870e2c2c00bf3f79954 
(Output & Code, Code requires JDK 14 with preview features and ASM)


As I am not an expert in any of those areas where classes showed up, 
and I don't know if it was an oversight, or if there is a good reason 
for not implementing AutoCloseable.
Implementing AutoCloseable is a double edged sword, a few IDEs warn 
about resource leaks based on that interface.
And treat an AutoCloseable passed to methods who return an 
AutoCloseable as the return value wraping the parameter.


I did look at a few classes:
* javax.xml.stream.XMLStreamReader:Javadoc: "Frees any resources 
associated with this Reader. This method does not close the 
underlying input source." Better not implement it?
* javax.naming.Context: Javadoc: "This method releases this context's 
resources immediately, instead of waiting for them to be released 
automatically by the garbage collector." Implement AutoCloseable?
* java.util.logging.Handler: Lifecycle seems to be managed by a 
LogManager. Better not implement AutoCloseable?
* jdk.internal.jrtfs.ExplodedImage: class is package private, 
overrides close() from SystemImage while increasing visibility to 
public.


I did not restrict my enumeration to public and exported types - it 
was easier not to do that and I'm lazy.


This touches many unrelated areas, but David Holmes suggested that I 
take it to core-libs-dev.
I know, I just did some static code analysis, but it seems that there 
might be some low hanging fruits.
And for public classes I wish to have at least some rationale why a 
class with a public void close() method doesn't implement AutoCloseable.


Thanks,
Johannes






Some Classes with a public void close() don't implement AutoCloseable

2020-04-15 Thread Johannes Kuhn
After failing to wrap a XMLStreamReader in a try-with-resources after 
discovering it's close() method,
I thought about checking what other classes have a public void close() 
method in the JDK but don't implement AutoCloseable.


So I wrote a small program that enumerates all classes present in in the 
jrt image with a public void close() method that does not

directly or indirectly implement AutoCloseable:
https://gist.github.com/DasBrain/8d50e02e35654870e2c2c00bf3f79954 
(Output & Code, Code requires JDK 14 with preview features and ASM)


As I am not an expert in any of those areas where classes showed up, and 
I don't know if it was an oversight, or if there is a good reason for 
not implementing AutoCloseable.
Implementing AutoCloseable is a double edged sword, a few IDEs warn 
about resource leaks based on that interface.
And treat an AutoCloseable passed to methods who return an AutoCloseable 
as the return value wraping the parameter.


I did look at a few classes:
* javax.xml.stream.XMLStreamReader:Javadoc: "Frees any resources 
associated with this Reader. This method does not close the underlying 
input source." Better not implement it?
* javax.naming.Context: Javadoc: "This method releases this context's 
resources immediately, instead of waiting for them to be released 
automatically by the garbage collector." Implement AutoCloseable?
* java.util.logging.Handler: Lifecycle seems to be managed by a 
LogManager. Better not implement AutoCloseable?
* jdk.internal.jrtfs.ExplodedImage: class is package private, overrides 
close() from SystemImage while increasing visibility to public.


I did not restrict my enumeration to public and exported types - it was 
easier not to do that and I'm lazy.


This touches many unrelated areas, but David Holmes suggested that I 
take it to core-libs-dev.
I know, I just did some static code analysis, but it seems that there 
might be some low hanging fruits.
And for public classes I wish to have at least some rationale why a 
class with a public void close() method doesn't implement AutoCloseable.


Thanks,
Johannes

Classes found:
com/sun/jdi/connect/spi/Connection
com/sun/jndi/dns/BaseNameClassPairEnumeration
com/sun/jndi/dns/DnsClient
com/sun/jndi/dns/DnsContext
com/sun/jndi/dns/Resolver
com/sun/jndi/ldap/AbstractLdapNamingEnumeration
com/sun/jndi/ldap/LdapCtx
com/sun/jndi/ldap/LdapReferralContext
com/sun/jndi/ldap/LdapSchemaCtx
com/sun/jndi/ldap/ext/StartTlsResponseImpl
com/sun/jndi/rmi/registry/BindingEnumeration
com/sun/jndi/rmi/registry/NameClassPairEnumeration
com/sun/jndi/rmi/registry/RegistryContext
com/sun/jndi/toolkit/dir/ContextEnumerator
com/sun/jndi/toolkit/dir/HierMemDirCtx
com/sun/jndi/toolkit/dir/HierMemDirCtx$BaseFlatNames
com/sun/jndi/toolkit/dir/LazySearchEnumerationImpl
com/sun/jndi/toolkit/url/GenericURLContext
com/sun/media/sound/AudioFloatFormatConverter$AudioFloatInputStreamChannelMixer 

com/sun/media/sound/AudioFloatFormatConverter$AudioFloatInputStreamResampler 


com/sun/media/sound/AudioFloatInputStream
com/sun/media/sound/AudioFloatInputStream$BytaArrayAudioFloatInputStream
com/sun/media/sound/AudioFloatInputStream$DirectAudioFloatInputStream
com/sun/media/sound/ModelAbstractOscillator
com/sun/media/sound/ModelDirector
com/sun/media/sound/ModelOscillatorStream
com/sun/media/sound/ModelStandardDirector
com/sun/media/sound/ModelStandardIndexedDirector
com/sun/media/sound/RIFFWriter$RandomAccessByteWriter
com/sun/media/sound/RIFFWriter$RandomAccessFileWriter
com/sun/media/sound/RIFFWriter$RandomAccessWriter
com/sun/media/sound/SoftAbstractResampler$ModelAbstractResamplerStream
com/sun/media/sound/SoftMainMixer
com/sun/media/sound/SoftMixingDataLine$AudioFloatInputStreamResampler
com/sun/media/sound/SoftMixingMainMixer
com/sun/media/sound/SoftMixingSourceDataLine$NonBlockingFloatInputStream
com/sun/naming/internal/VersionHelper$InputStreamEnumeration
com/sun/org/apache/xerces/internal/impl/XMLStreamFilterImpl
com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl
com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader
com/sun/org/apache/xml/internal/serializer/EmptySerializer
com/sun/org/apache/xml/internal/serializer/SerializationHandler
com/sun/org/apache/xml/internal/serializer/SerializerBase
com/sun/org/apache/xml/internal/serializer/ToHTMLSAXHandler
com/sun/org/apache/xml/internal/serializer/ToUnknownStream
com/sun/org/apache/xml/internal/serializer/WriterChain
com/sun/tools/javac/api/JavacTaskPool$ReusableContext$ReusableJavaCompiler
com/sun/tools/javac/file/JavacFileManager$1
com/sun/tools/javac/file/JavacFileManager$ArchiveContainer
com/sun/tools/javac/file/JavacFileManager$Container
com/sun/tools/javac/file/JavacFileManager$DirectoryContainer
com/sun/tools/javac/file/JavacFileManager$JRTImageContainer
com/sun/tools/javac/file/Locations
com/sun/tools/javac/main/JavaCompiler
com/sun/tools/javac/processing/JavacProcessingEnvironment$DiscoveredProcessors 



Re: [PATCH] Simplification proposal regarding TYPE-field initialization in primitive wrappers

2019-11-26 Thread Johannes Kuhn
Hi,

I saw Remi's reply after I sent my reply.
The questions I asked were just to confirm that my suspicion (int.class gets 
compiled into Integer.TYPE) were true - I am currently on mobile, so I couldn't 
test it myself.

In short, my mail doesn't provide any additional value, and if I had seen 
Remi's reply, I wouldn't have sent mine.

Best regards,
Johannes

On November 26, 2019 10:10:02 PM GMT+01:00, "Сергей Цыпанов" 
 wrote:
>Hello,
>
>> I suspect that it will print null, because to my knowledge, int.class
>will be compiled to a getstatic Integer.TYPE, so your test basically
>tests if Integer.TYPE == Integer.TYPE.
>
>right, Remi pointed this out in his response.
>
>> Also, do the tier1 tests succeed with your patch?
>
>I'm going to do that as far as my work station is fixed, hope tomorrow.
>Apparently, something is going to go wrong :) Anyway, I'll notify about
>results when this is done.
>
>Regards,
>Sergey Tsypanov
>
>
>26.11.2019, 21:57, "Johannes Kuhn" :
>> On November 26, 2019 8:29:06 PM GMT+01:00, "Сергей Цыпанов"
> wrote:
>>> Hello,
>>>
>>> while using java.lang.Integer.TYPE I've found out that currently
>>> wrapper classes for primitives initialize their own TYPE-fields by
>>> calling native method java.lang.Class.getPrimitiveClass().
>>>
>>> This can be simplified by changing existing declaration (here for
>>> java.lang.Integer)
>>>
>>> @SuppressWarnings("unchecked")
>>> public static final Class TYPE = (Class)
>>> Class.getPrimitiveClass("int");
>>>
>>> to
>>>
>>> public static final Class TYPE = int.class;
>>>
>>> This is likely to improve start-up time as Class.getPrimitiveClass()
>is
>>> called 9 times (8 primitive type wrappers + java.lang.Void), after
>the
>>> change this method is not called at all and thus can be removed
>along
>>> with its backing C++ code on VM-side. The fields are initialized
>purely
>>> on Java side.
>>>
>>> I've verified correctness of the substitution with this test run on
>JDK
>>> 11
>>>
>>> @Test
>>> void name() {
>>>   assert void.class == Void.TYPE;
>>>   assert boolean.class == Boolean.TYPE;
>>>   assert byte.class == Byte.TYPE;
>>>   assert char.class == Character.TYPE;
>>>   assert short.class == Short.TYPE;
>>>   assert int.class == Integer.TYPE;
>>>   assert long.class == Long.TYPE;
>>>   assert float.class == Float.TYPE;
>>>   assert double.class == Double.TYPE;
>>> }
>>>
>>> The patch is attached.
>>>
>>> Regards,
>>> Sergey Tsypanov
>>
>> Hi,
>> a few questions:
>> What does System.out.println(int.class); with your patch print? "int"
>or "null"?
>>
>> I suspect that it will print null, because to my knowledge, int.class
>will be compiled to a getstatic Integer.TYPE, so your test basically
>tests if Integer.TYPE == Integer.TYPE.
>>
>> Also, do the tier1 tests succeed with your patch?
>>
>> With best regards,
>> Johannes


Re: New candidate JEP: 370: Foreign-Memory Access API

2019-11-26 Thread Johannes Kuhn
Hi,

Just had the chance to look at the proposal, and I have a small suggestion:
MemorySegmenent::mapFromPath should state that it can throw a SecurityException 
if a SecurityManager is installed in the javadoc.
The description can be copied from FileChannel::open.

With best regards,
Johannes


Re: [PATCH] Simplification proposal regarding TYPE-field initialization in primitive wrappers

2019-11-26 Thread Johannes Kuhn



On November 26, 2019 8:29:06 PM GMT+01:00, "Сергей Цыпанов" 
 wrote:
>Hello,
>
>while using java.lang.Integer.TYPE I've found out that currently
>wrapper classes for primitives initialize their own TYPE-fields by
>calling native method java.lang.Class.getPrimitiveClass().
>
>This can be simplified by changing existing declaration (here for
>java.lang.Integer)
>
>@SuppressWarnings("unchecked")
>public static final Class  TYPE = (Class)
>Class.getPrimitiveClass("int");
>
>to
>
>public static final Class  TYPE = int.class;
>
>This is likely to improve start-up time as Class.getPrimitiveClass() is
>called 9 times (8 primitive type wrappers + java.lang.Void), after the
>change this method is not called at all and thus can be removed along
>with its backing C++ code on VM-side. The fields are initialized purely
>on Java side.
>
>I've verified correctness of the substitution with this test run on JDK
>11
>
>@Test
>void name() {
>  assert void.class == Void.TYPE;
>  assert boolean.class == Boolean.TYPE;
>  assert byte.class == Byte.TYPE;
>  assert char.class == Character.TYPE;
>  assert short.class == Short.TYPE;
>  assert int.class == Integer.TYPE;
>  assert long.class == Long.TYPE;
>  assert float.class == Float.TYPE;
>  assert double.class == Double.TYPE;
>}
>
>The patch is attached.
>
>Regards,
>Sergey Tsypanov
Hi,
a few questions:
What does System.out.println(int.class); with your patch print? "int" or "null"?

I suspect that it will print null, because to my knowledge, int.class will be 
compiled to a getstatic Integer.TYPE, so your test basically tests if 
Integer.TYPE == Integer.TYPE.

Also, do the tier1 tests succeed with your patch?

With best regards,
Johannes


Re: Looking for Sponsor: JDK-8229959 Convert proxy class to use constant dynamic

2019-11-23 Thread Johannes Kuhn

On 11/23/2019 10:40 PM, Brian Goetz wrote:




Finally, we can benchmark the current approach against the LDC 
approach on a per-Method basis.  The LDC approach may well be doing 
more work per Method, so it's a tradeoff to determine whether 
deferring that work is a win.


By this last bit, I mean JMH'ing:

    Method m1() {
   return Class.forName("java.lang.Object").getMethod("equals", 
new Class[] { Class.forName("java.lang.Object") });

    }

vs

    Method m2() {
    return bootstrap(... constant bootstrap args for above ...)
    }


Thanks for the pointers, I did run one round on my machine - I don't 
have a dedicated one - so, maybe treat it with a fine grain of salt.
The test code and results can be found here: 
https://gist.github.com/DasBrain/501fd5ac1e2ade2e28347ec666299473


Benchmark  Mode  Cnt Score    Error  Units
ProxyFindMethod.getMethod thrpt   25  1505594.515 ± 
42238.663  ops/s
ProxyFindMethod.lookupMethod  thrpt   25   760530.602 ± 
25074.003  ops/s
ProxyFindMethod.lookupMethodCachedMH  thrpt   25  4327814.284 ± 
103456.616  ops/s


I wrote three tests, the first one (getMethod) uses the 
Class.forName().getMethod(), the second uses lookup.findVirtual to get 
the MethodHandle every iteration, while the third one caches it in a 
static final field.


My interpretation: If the method has to be looked up (and the VM has to 
do that at least once), then the old getMethod call is faster.
I also suspect the Class.forName call to be optimized - on some old java 
versions, iirc pre-1.5, Foo.class was compiled into 
Class.forName("Foo"), so the JIT might do something there.

So, now I have to learn how to read assembly. Good.



Re: Looking for Sponsor: JDK-8229959 Convert proxy class to use constant dynamic

2019-11-23 Thread Johannes Kuhn

On 11/23/2019 6:09 PM, Brian Goetz wrote:

Thanks for the examples.

A few comments:

  - A reasonable place to consider putting the bootstrap is in Proxy 
itself.  I am not sure that ConstantBootstraps is the right place (or 
anywhere in JLI for that matter) unless Method is retrofitted to 
implement Constable, which is problematic given that Methods are not 
constants.
Yes, Method implementing Constable might not be the right thing, because 
Method is not immutable. Adding the bootstrap method to j.l.r.Proxy is a 
good alternative.
  - In the department of “future things that might be  applied here” 
(Remi started it), this is a perfect application for lazy statics.  
But we don’t have those yet.


What Remi and Mandy suggested is to pass the Method instances that we 
already use to spin the bytecode to the new class, which avoids an other 
round of method lookups.
While I like the idea, it relies on on future things. I will try to 
write a prototype for that.


  - The main benefit here is that it makes proxy creation faster.  
However, given the amount of work that goes on at proxy creation 
(reflection, byte code spinning, class loading), its not clear how 
much of the cost is initializing the proxy class.  Some benchmarking 
to establish the cost benefit here would be good.  (If we are spinning 
the proxy at jlink time, then the benefit is probably greater.)


Overall, the translation approach seems sound but I would suggest that 
we clarify the benefits a little bit before embarking.


I just finished the first prototype, which can be found at 
https://gist.github.com/DasBrain/7766bedfbc8b76ba6a0ee66a54ba97ed - it 
contains a patch, the javap output of a generated proxy class with and 
without that patch, and the code I used to dump the proxy class. "make 
run-test-tier1" passes all JDK tests with the patch. I hope this will 
help the discussion a bit.


The other benefit I talked about is: It makes to code easier, because 
it's less code and it's a greater locality. I know, this is hard to 
measure.


Everything was spawned by a small sentence Remi wrote on this list:

A follow up should to use constant dynamic (introduce in Java 11) to 
get the j.l.r.Method object instead of pre-calculating all of them in 
the static init block.
The idea is that a ldc on a constant dynamic with bootstrap method 
that takes a MethodHandle as parameter (as boostrap argument) can 
return the corresponding Method by using Lookup.revealDirect + reflectAs.

The bootstrap method can be added to j.l.i.ConstantBootstraps


https://mail.openjdk.java.net/pipermail/core-libs-dev/2019-August/061923.html 



But there were never a real discussion about the benefits yet. It's good 
that we have one now.


As I am a novice JMH user, I don't trust myself to write good benchmarks 
that actually measure what I want to measure, not confirm what I would 
like it to be


Re: Looking for Sponsor: JDK-8229959 Convert proxy class to use constant dynamic

2019-11-22 Thread Johannes Kuhn

On 22.11.2019 22:41, Remi Forax wrote:

i wonder if some codes in the wild rely on that ?

I don't think some code does, but you never know.

There is perhaps a better way, as part of the branch nestmates of valhalla, 
Mandy has added a way to transfer a live object to a Class when defining it, 
with that you can send all the Methods as an array and in the bootstrap method 
of a condy, access to the right method by extracting it from the array using an 
index.
It will avoid the whole serialization/deserialization of Methods dance.


That is a better idea - and could be done today using 
Unsafe.defineAnonymousClass - If it didn't need a host class.



Here is an example:
   https://gist.github.com/forax/d0f0034190bc479b86ce977fb94ca176

I believe those changes are planned for Java 14 so will be integrated very soon.


It looks like the class is defined using 
Lookup.defineHiddenClassWithClassData - in the current proxy 
implementation there is no lookup object.

Also, I'm not sure if the defined proxy class needs to be findable.
In short: I did not do an evaluation on what unspecified parts of a 
proxy can be changed without breaking someones cod





Re: Looking for Sponsor: JDK-8229959 Convert proxy class to use constant dynamic

2019-11-22 Thread Johannes Kuhn
Last mail got converted from HTML into plaintext, which dropped some 
significant whit espace. So, again, doing it by hand this time.


On 22.11.2019 20:52, Brian Goetz wrote:
> For those that are not intimately familiar with the mechanics of 
proxy class generation, it would be great to flesh this out with a code 
example, that shows the proposed old and new translation. This would 
make it easier for folks to evaluate the benefits and costs of the 
approach, and possibly suggest improvements.

>
> On 11/21/2019 10:23 PM, Johannes Kuhn wrote:
>>
>> * What benefits would such a change have?
>> First, it allows us to drop the static final fields and the class 
initializer for the generated proxy classes.
>> Second, it allows the code (both generated and generator) to be more 
clear by moving the essential parts together.
>> Third, it might bring some performance improvement, because the 
j.l.r.Method lookup is delayed to it's first use - which in some cases 
might never happen.

>
Thanks for the suggestion. A proxy can be used to create an 
implementation of one or more interfaces at run time.
I just let Java 13 dump a generated Proxy and decompiled it using JD. 
This is the result:


package com.sun.proxy;
// imports ...;
public final class $Proxy0 extends Proxy implements Runnable {
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  public $Proxy0(InvocationHandler paramInvocationHandler) { 
super(paramInvocationHandler); }


  public final boolean equals(Object paramObject) {
    try {
  return ((Boolean)this.h.invoke(this, m1, new Object[] { 
paramObject })).booleanValue();

    } catch (Error|RuntimeException error) {
  throw error;
    } catch (Throwable throwable) {
  throw new UndeclaredThrowableException(throwable);
    }
  }

  public final void run() {
    try {
  this.h.invoke(this, m3, null);
  return;
    } catch (Error|RuntimeException error) {
  throw error;
    } catch (Throwable throwable) {
  throw new UndeclaredThrowableException(throwable);
    }
  }

  public final String toString() {
    try {
  return (String)this.h.invoke(this, m2, null);
    } catch (Error|RuntimeException error) {
  throw error;
    } catch (Throwable throwable) {
  throw new UndeclaredThrowableException(throwable);
    }
  }

  public final int hashCode() {
    try {
  return ((Integer)this.h.invoke(this, m0, null)).intValue();
    } catch (Error|RuntimeException error) {
  throw error;
    } catch (Throwable throwable) {
  throw new UndeclaredThrowableException(throwable);
    }
  }

  static  {
    try {
  m1 = Class.forName("java.lang.Object").getMethod("equals", new 
Class[] { Class.forName("java.lang.Object") });
  m3 = Class.forName("java.lang.Runnable").getMethod("run", new 
Class[0]);
  m2 = Class.forName("java.lang.Object").getMethod("toString", new 
Class[0]);
  m0 = Class.forName("java.lang.Object").getMethod("hashCode", new 
Class[0]);

  return;
    } catch (NoSuchMethodException noSuchMethodException) {
  throw new NoSuchMethodError(noSuchMethodException.getMessage());
    } catch (ClassNotFoundException classNotFoundException) {
  throw new NoClassDefFoundError(classNotFoundException.getMessage());
    }
  }
}

The new implementation using ASM generates a similar class.
I intend to replace the the references to m0, m1... in the generated 
code through an LDC instruction, and remove the code that generates the 
fields and the static class initializer.


The resulting code would look a something like this:

package com.sun.proxy;
// imports ...;
public final class $Proxy0 extends Proxy implements Runnable {

  public $Proxy0(InvocationHandler paramInvocationHandler) { 
super(paramInvocationHandler); }


  public final boolean equals(Object paramObject) {
    try {
  return ((Boolean)this.h.invoke(this, __LDC(__MethodHandle
(com.sun.proxy.$Proxy0::$bootstap, "_", Method.class,
__MethodHandle(java.lang.Object::equals)), new Object[] { paramObject 
})).booleanValue();

    } catch (Error|RuntimeException error) {
  throw error;
    } catch (Throwable throwable) {
  throw new UndeclaredThrowableException(throwable);
    }
  }

  // repeat for run(), hashCode() and equals(Object other)

  private static final Method $bootstrap(Lookup lookup, String ignored, 
Class clazz, MethodHandle mh) {

    return lookup.revealDirect(mh).reflectAs(clazz, lookup);
  }

}

I used __LDC as placeholder for the LDC bytecode instruction (limited to 
constant dynamic), and __MethodHandle for a MethodHandle in the constant 
pool.
This means the Method is only looked up when the proxy method is called 
for the first time.


In the actual source code (the generating code), it means that the 
following methods can be dropped:
P

Re: Looking for Sponsor: JDK-8229959 Convert proxy class to use constant dynamic

2019-11-22 Thread Johannes Kuhn

On 22.11.2019 20:52, Brian Goetz wrote:
For those that are not intimately familiar with the mechanics of proxy 
class generation, it would be great to flesh this out with a code 
example, that shows the proposed old and new translation. This would 
make it easier for folks to evaluate the benefits and costs of the 
approach, and possibly suggest improvements.


On 11/21/2019 10:23 PM, Johannes Kuhn wrote:


* What benefits would such a change have?
First, it allows us to drop the static final fields and the class 
initializer for the generated proxy classes.
Second, it allows the code (both generated and generator) to be more 
clear by moving the essential parts together.
Third, it might bring some performance improvement, because the 
j.l.r.Method lookup is delayed to it's first use - which in some 
cases might never happen.


Thanks for the suggestion. A proxy can be used to create an 
implementation of one or more interfaces at run time.
I just let Java 13 dump a generated Proxy and decompiled it using JD. 
This is the result:


packagecom.sun.proxy;
//imports...;
publicfinalclass$Proxy0extendsProxyimplementsRunnable{
privatestaticMethodm1;
privatestaticMethodm3;
privatestaticMethodm2;
privatestaticMethodm0;

public$Proxy0(InvocationHandlerparamInvocationHandler){super(paramInvocationHandler);}

publicfinalbooleanequals(ObjectparamObject){
try{
return((Boolean)this.h.invoke(this,m1,newObject[]{paramObject})).booleanValue();
}catch(Error|RuntimeExceptionerror){
throwerror;
}catch(Throwablethrowable){
thrownewUndeclaredThrowableException(throwable);
}
}

publicfinalvoidrun(){
try{
this.h.invoke(this,m3,null);
return;
}catch(Error|RuntimeExceptionerror){
throwerror;
}catch(Throwablethrowable){
thrownewUndeclaredThrowableException(throwable);
}
}

publicfinalStringtoString(){
try{
return(String)this.h.invoke(this,m2,null);
}catch(Error|RuntimeExceptionerror){
throwerror;
}catch(Throwablethrowable){
thrownewUndeclaredThrowableException(throwable);
}
}

publicfinalinthashCode(){
try{
return((Integer)this.h.invoke(this,m0,null)).intValue();
}catch(Error|RuntimeExceptionerror){
throwerror;
}catch(Throwablethrowable){
thrownewUndeclaredThrowableException(throwable);
}
}

static{
try{
m1=Class.forName("java.lang.Object").getMethod("equals",newClass[]{Class.forName("java.lang.Object")});
m3=Class.forName("java.lang.Runnable").getMethod("run",newClass[0]);
m2=Class.forName("java.lang.Object").getMethod("toString",newClass[0]);
m0=Class.forName("java.lang.Object").getMethod("hashCode",newClass[0]);
return;
}catch(NoSuchMethodExceptionnoSuchMethodException){
thrownewNoSuchMethodError(noSuchMethodException.getMessage());
}catch(ClassNotFoundExceptionclassNotFoundException){
thrownewNoClassDefFoundError(classNotFoundException.getMessage());
}
}
}

The new implementation using ASM generates a similar class.
I intend to replace the the references to m0, m1... in the generated 
code through an LDC instruction, and remove the code that generates the 
fields and the static class initializer.


The resulting code would look a something like this:

packagecom.sun.proxy;
//imports...;
publicfinalclass$Proxy0extendsProxyimplementsRunnable{

public$Proxy0(InvocationHandlerparamInvocationHandler){super(paramInvocationHandler);}

publicfinalbooleanequals(ObjectparamObject){
try{
return((Boolean)this.h.invoke(this,__LDC(__MethodHandle 
(com.sun.proxy.$Proxy0::$bootstap, "_", Method.class, 
__MethodHandle(java.lang.Object::equals)),newObject[]{paramObject})).booleanValue();

}catch(Error|RuntimeExceptionerror){
throwerror;
}catch(Throwablethrowable){
thrownewUndeclaredThrowableException(throwable);
}
}

// repeat for run(), hashCode() and equals(Object other)
private static final Method $bootstrap(Lookup lookup, String ignored, 
Class clazz, MethodHandle mh) { return 
lookup.revealDirect(mh).reflectAs(clazz, lookup); }

}

I used __LDC as placeholder for the LDC bytecode instruction (limited to 
constant dynamic), and __MethodHandle for a MethodHandle in the constant 
pool.
This means the Method is only looked up when the proxy method is called 
for the first time.


In the actual source code (the generating code), it means that the 
following methods can be dropped:
ProxyGenerator.generateStaticInitializer() 
https://hg.openjdk.java.net/jdk/jdk/file/a2a921609481/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java#l576
ProxyGenerator.ProxyMethod.codeFieldInitialization(MethodVisitor, 
String) 
https://hg.openjdk.java.net/jdk/jdk/file/a2a921609481/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java#l576


It will require the addition of a new method, which creates the 
$bootstrap method, and a change 
ProxyGenerator.ProxyMethod.generateMethod to emit an LDC instruction 
instead of a GETSTATIC.


The next step is to remove the now unused ProxyMethod.methodFieldName 
and it's dependencies (constructor, th

Looking for Sponsor: JDK-8229959 Convert proxy class to use constant dynamic

2019-11-21 Thread Johannes Kuhn

Hi everyone,

a few hours ago I signed the Oracle Contributor Agreement.
I'd like to work on JDK-8229959: Convert proxy class to use constant 
dynamic.


Without further ado, here are some questions and answers you may ask:

* What are you exactly planing to do?
I'd like to replace the GETSTATIC instruction with an LDC instruction in 
the current generated bytecode for the proxies.


* What benefits would such a change have?
First, it allows us to drop the static final fields and the class 
initializer for the generated proxy classes.
Second, it allows the code (both generated and generator) to be more 
clear by moving the essential parts together.
Third, it might bring some performance improvement, because the 
j.l.r.Method lookup is delayed to it's first use - which in some cases 
might never happen.


* Are you able to write such a patch?
Yes. I have some experience with the Java bytecode, ASM and ConstantDynamic.

* But java.lang.reflect.Method is not immutable/persistent?
That's not a question, but you are right. j.l.r.Method has 
setAccessible, modifying the Method instance. Still, the current 
implementation shares the same Method instance with all proxies with the 
same interfaces in the same ClassLoader.


* What should the bootstrap method look like?
The bootstrap method will take one additional argument, a direct 
MethodHandle to the to be resolved method, and should crack it using 
it's passed Lookup and then reflect it as Method. In other words, it 
should do `return lookup.revealDirect(mh).reflectAs(Method.class, lookup);`


*  Where should this bootstrap method reside?
I'm glad you asked. After some thoughts, there are two promising places 
where I could put it:

a) As private static method in the proxy itself.
Benefits: No public API changes. Also allows easy migration to option b) 
if pursued later.

Downsides: The bootstrap method will be duplicated into every proxy class.
b) As a public static method in the java.* namespace, preferably in 
java.lang.invoke.ConstantBootstraps.

Benefits: Only one single implementation in the JVM.
Downside: Changes to the public API. Also leads to other questions like 
"Should j.l.r.Member implement Constable?" and "Should I add a subclass 
of j.l.c.DynamicConstantDesc for this bootstrap method?"
I prefer option a), but I'm fine with both options. Please let me know 
what you think, or if you think of a better way.


* What do I expect from my Sponsor?
I expect my sponsor lo believe that this change will improve the 
OpenJDK. If consensus shows a preference for option b) above (bootstrap 
in j.l.i.ConstantBootstaps), a guidance what requests have to be made 
and where. In that case, I volunteer to write those requests and send 
them to my sponsor, who can (at their sole discretion) forward it to the 
relevant places.


If you have any additional questions, please don't hesitate to answer to 
this mail. I will try to answer all questions to the best of my ability.


With best regards,
Johannes Kuhn



Re: RFR JDK-8233527: Update Lookup::hasPrivateAccess and Lookup::defineClass spec w.r.t. full power lookup

2019-11-13 Thread Johannes Kuhn

On 13.11.2019 20:07, Mandy Chung wrote:
Thank you for all those changes. It fixed two of my reported bugs 
(JDK-8209005, JDK-8209078).


Thanks for filing these good reports.   JDK-8173978 resolved the 
issues reported by JDK-8209005 and JDK-8209078.

I'm happy I could help.
It also makes my suggested workaround for JDK-8230636 not longer 
possible. Thanks for picking that up too.


I just have a question about the requirement of 
MethodHandles.privateLookupIn: As it requires that the originating 
lookup has both PRIVATE and MODULE access, it sounds a lot like full 
privilege access. Should this be reworded?




The two bullets about the caller lookup object must have MODULE and 
PRIVATE are important explanation for it to require such access.


Maybe I can add a bullet to say "The caller lookup object must have 
full privilege access" and then move those two bullets as sub-bullets 
under it.


What do you think?
This is a good idea, because full privilege access is a new concept, and 
should be mentioned at the places where it is used.
Also, with the current specification, I don't see a way to abuse 
jdk.unsupported's privileged access into java.base (which IMHO caused 
the entire rework).


Thanks for looking at this.

Mandy


Shameless plug: I once asked on Stackoverflow if untrusted code running 
with a SecurityManager and -illegal-access=deny but granting 
|ReflectPermission("supressAccessChecks") |could escape the sandbox[1]. 
I found a way to escape the sandbox, which relies on the power of the 
Lookup returned by privateLookupIn.
As this has been changed, I wonder if this escape was ever intended in 
the first place. Are there any resources out there that can help answer 
this question?


Thanks,
Johannes

[1]: 
https://stackoverflow.com/questions/51712903/is-it-safe-to-grant-untrusted-code-supressaccesschecks-when-illegal-access-de




Re: RFR JDK-8233527: Update Lookup::hasPrivateAccess and Lookup::defineClass spec w.r.t. full power lookup

2019-11-13 Thread Johannes Kuhn

On 11.11.2019 22:23, Mandy Chung wrote:
This is a follow-up of JDK-8226916. Lookup::hasPrivateAccess intends 
to test if this lookup is a full-power lookup; that is created by the 
original caller class calling MethodHandles::lookup. The current 
specification for Lookup::hasPrivateAccess returns true if the lookup 
modes contain PRIVATE but it does not check MODULE bit.


This patch also clarifies the capabilities w.r.t PRIVATE access and 
full-power access. The security permission check is performed if the 
Lookup is not a full power lookup and therefore Lookup::defineClass 
spec should be updated to perform security permission check if the 
security manager is present and this lookup refuses access, consistent 
with other Lookup operations.


http://cr.openjdk.java.net/~mchung/jdk14/8233527/webrev.02/
http://cr.openjdk.java.net/~mchung/jdk14/8233527/specdiff/

CSR: https://bugs.openjdk.java.net/browse/JDK-8233726

thanks
Mandy


Thank you for all those changes. It fixed two of my reported bugs 
(JDK-8209005, JDK-8209078).
It also makes my suggested workaround for JDK-8230636 not longer 
possible. Thanks for picking that up too.


I just have a question about the requirement of 
MethodHandles.privateLookupIn: As it requires that the originating 
lookup has both PRIVATE and MODULE access, it sounds a lot like full 
privilege access. Should this be reworded?


Also, with the current specification, I don't see a way to abuse 
jdk.unsupported's privileged access into java.base (which IMHO caused 
the entire rework).


thanks,
Johannes



Re: [JDK-8209078] Unable to call default interface methods from named module

2018-09-17 Thread Johannes Kuhn
Hi,

thanks for your quick reply.

On 16/09/2018 11:15, Alan Bateman wrote:
> On 14/09/2018 20:34, Johannes Kuhn wrote:
>> :
>>
>> 1. Use Case:
>>
>> The most obvious use case is to to "implement" default methods in
>> instances created by j.l.r.Proxy. An implementation of
>> j.l.r.InvocationHandler that handles default methods could look like
>> this:
>>
>>  public Object invoke(Object proxy, Method method, Object[] args)
>>  throws Throwable {
>>  if (method.isDefault()) {
>>  MethodType mt = methodType(method.getReturnType(),
>>  method.getParameterTypes());
>>  Class declaringClass = method.getDeclaringClass();
>>  Lookup l = MethodHandles.lookup();
>>  MethodHandle mh = l.findSpecial(declaringClass,
>>  method.getName(), mt, declaringClass)
>>     .asFixedArity()
>>     .bindTo(proxy);
>>  return mh.invokeWithArguments(args);
>>  }
>>  // Handle the other methods
>>  return null;
>>  }
>>
>> Such a feature is very valuable so the InvocationHandler does not break
>> if an interface is evolved by adding new default methods.
> The common case will be a public interface in an exported package in
> which case the proxy will be generated in the unnamed module of the
> specified class loader. This means you can create a full-power lookup on
> the proxy class with:
> 
> Class proxyClass = proxy.getClass();
> this.getClass().getModule().addReads(proxyClass.getModule());
> Lookup l = MethodHandles.privateLookupIn(proxyClass,
> MethodHandles.lookup());
> 
> If you invoke findSpecial on this lookup then I would expect it should
> work.

Thank you, this works fine. Unless you don't have
j.l.r.ReflectPermission("suppressAccessChecks").

I try to avoid requiring additional permissions if possible, and code in
an unnamed module does not need privateLookupIn.

Also j.l.r.ReflectPermission("suppressAccessChecks") is considered a
dangerous permission that allows a full sandbox escape.
> 
> There can be cases where the proxy is encapsulated (because the
> interfaces are not public or not in exported packages) but I assume you
> don't need to be concerned with those for now.
> 

Right, I am not concerned about that now.

>> :
>>
>>
>> 3. Cause of the discrepancy between lookup class in named module vs
>> unnamed module
>>
>> As Mandy Chung observed:
>>
>>> IAE is thrown because the implementation calls Lookup::in teleporting
>>> to a Lookup of the special class which lost all access since the
>>> caller class and the requested lookup class are in different modules.
>> This behavior is documented in the Lookup.in() [6]:
>>
>>> * If the old lookup class is in a named module, and the new lookup
>>> class is in a different module M, then no members, not even public
>>> members in M's exported packages, will be accessible. The exception to
>>> this is when this lookup is publicLookup, in which case PUBLIC access
>>> is not lost.
>>> * If the old lookup class is in an unnamed module, and the new lookup
>>> class is a different module then MODULE access is lost.
>> This strikes me as a little bit odd, so I looked around for the
>> reasoning for this difference, and found an old discussion on jigsaw-dev
>> [7]. I especially found this mail from Alan Bateman [8] interesting,
>> where he gave a reasoning for this:
>>
>>> Preserved but perhaps with the (initially surprising) consequence that
>>> all access is lost when m(LC) is a named module and m(A) is a
>>> different module. This arises because the two modules may read very
>>> different sets of modules, the intersection cannot be expressed via a
>>> lookup class + modes.
>> While I agree that intersection might not be expressed via lookup class
>> + modes, I don't think that it is necessary to express that. Instead
>> don't allow any lookup on members in a different module if the MODULE
>> flag is not set.
>>
> Qualified exports complicated this, as does readability. JDK-8173978 [1]
> tracks the need to support checking the intersection.
> 

I also had some thoughts about what semantics Lookup.in() can have.

A Lookup for class A can only be created in 3 ways:

* MethodHandles.lookup() called from A - full access
* MethodHandles.privateLookupIn() - full access
* Lookup.in() - drops modes depending on the distance.

The reasoning for Lookup.in() should always be:

** If a mode bit is set, then the o

[JDK-8209078] Unable to call default interface methods from named module

2018-09-16 Thread Johannes Kuhn
Hi everyone,

I recently reported JDK-8209078 "Unable to call default method from
interface in another module from named module" [1].

It is possible to call any default interface method directly using
MethodHandles.lookup().findSpecial(Interf.class, "defaultMethodName",
..., Intef.class).invoke(...);

This only works if the caller is in an unnamed module or Interf is in
the same module as the caller.

I now want to share some thoughts about this feature, and an idea how it
could be fixed, but this probably requires further discussion.

1. Use Case:

The most obvious use case is to to "implement" default methods in
instances created by j.l.r.Proxy. An implementation of
j.l.r.InvocationHandler that handles default methods could look like this:

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.isDefault()) {
MethodType mt = methodType(method.getReturnType(),
method.getParameterTypes());
Class declaringClass = method.getDeclaringClass();
Lookup l = MethodHandles.lookup();
MethodHandle mh = l.findSpecial(declaringClass,
method.getName(), mt, declaringClass)
   .asFixedArity()
   .bindTo(proxy);
return mh.invokeWithArguments(args);
}
// Handle the other methods
return null;
}

Such a feature is very valuable so the InvocationHandler does not break
if an interface is evolved by adding new default methods.

2. Documentation:

When I faced the problem above, I did a search on how to invoke default
methods on a proxy.

The above code was inspired by this mail [2] from John Rose, where he
mentions JDK-8130227 "JEP 274: Enhanced Method Handles" [3][4].

This is the only official documentation I could find on this feature.

Indeed, even the Javadoc for findSpecial [5] states that my code above
should not successfully run:

> Before method resolution, if the explicitly specified caller class is
> not identical with the lookup class, or if this lookup object does not
> have private access privileges, the access fails.

The specified caller class in the example above is the interface itself,
not the lookup class.

The documentation has to be at least changed to reflect this feature.

3. Cause of the discrepancy between lookup class in named module vs
unnamed module

As Mandy Chung observed:

> IAE is thrown because the implementation calls Lookup::in teleporting
> to a Lookup of the special class which lost all access since the
> caller class and the requested lookup class are in different modules.

This behavior is documented in the Lookup.in() [6]:

> * If the old lookup class is in a named module, and the new lookup
> class is in a different module M, then no members, not even public
> members in M's exported packages, will be accessible. The exception to
> this is when this lookup is publicLookup, in which case PUBLIC access
> is not lost.
> * If the old lookup class is in an unnamed module, and the new lookup
> class is a different module then MODULE access is lost.

This strikes me as a little bit odd, so I looked around for the
reasoning for this difference, and found an old discussion on jigsaw-dev
[7]. I especially found this mail from Alan Bateman [8] interesting,
where he gave a reasoning for this:

> Preserved but perhaps with the (initially surprising) consequence that
> all access is lost when m(LC) is a named module and m(A) is a
> different module. This arises because the two modules may read very
> different sets of modules, the intersection cannot be expressed via a
> lookup class + modes.

While I agree that intersection might not be expressed via lookup class
+ modes, I don't think that it is necessary to express that. Instead
don't allow any lookup on members in a different module if the MODULE
flag is not set.

But this is only a suggestion. It's up to you to decide how to deal with
this.

Please keep up the good work you are doing, and I hope this mail will
help you fixing this bug.

Thanks for your time,
Johannes Kuhn

[1]: https://bugs.openjdk.java.net/browse/JDK-8209078
[2]:
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-January/010741.html
[3]: https://bugs.openjdk.java.net/browse/JDK-8130227
[4]: http://openjdk.java.net/jeps/274
[5]:
https://docs.oracle.com/javase/10/docs/api/java/lang/invoke/MethodHandles.Lookup.html#findSpecial(java.lang.Class,java.lang.String,java.lang.invoke.MethodType,java.lang.Class)
[6]:
https://docs.oracle.com/javase/10/docs/api/java/lang/invoke/MethodHandles.Lookup.html#in(java.lang.Class)
[7]:
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005751.html
[8]:
http://mail.openjdk.java.net/pipermail/jigsaw-dev/2015-December/005768.html