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

Remi Forax forax at univ-mlv.fr
Mon Apr 18 20:41:26 UTC 2022


----- Original Message -----
> From: "liach" <duke at openjdk.java.net>
> To: "core-libs-dev" <core-libs-dev at openjdk.java.net>, "security-dev" <security-dev at openjdk.java.net>
> Sent: Monday, April 18, 2022 10:01:39 PM
> Subject: Re: RFR: JDK-8242888: Convert dynamic proxy to hidden classes

> On Sun, 17 Apr 2022 16:17:30 GMT, liach <duke at openjdk.java.net> 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.
> 
> I strongly recommend a new API over revamping `Proxy` itself.
> https://github.com/forax/hidden_proxy would be a good prototype that serves
> most needs of the current Proxy API (except a few, like invoking default
> superinterface method). 

The third parameter of defineProxy() is a lambda which is called for each method that can be overriden, either toString/equals/hashCode but also any default methods,
if the lambda return true, the method is overriden, otherwise the default implementation is used.

> With hidden classes, I don't see much value in leaving
> the new API's produced instance in separate modules; what we have for hidden
> classes should be fine for the most part.
> 
> Imo the main obstacle is still the handling of serialization. The annotations
> are serializable, but currently hidden classes do not work with serialization
> at all and must use `writeReplace` and `readResolve`. And how to migrate
> annotations off proxies without breaking serialization is still a question as
> well. Maybe we can upgrade invocation handlers to allow them to declare custom
> `readResolve` logic for the proxy to facilitate migration away. How the new API
> will treat serialization is still undetermined.

yes, i suppose that like with lambdas, we need a special overload of defineProxy that automatically implements writeReplace() and use a specific class SerializableProxy (mirroring how SerializableLambda works).

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


More information about the security-dev mailing list