Re: proxy an interface and call a default method
That looks quite good to me On 03.06.2016 11:51, Peter Levart wrote: On 06/02/2016 06:34 PM, fo...@univ-mlv.fr wrote: So perhaps, instead of providing a Proxy::findSuper method that returns a pre-bound MH, there could simply be a method like the following in the Proxy class: public final Object invokeSuper(Class interfaze, String methodName, MethodType methodType, Object ... args) { ... } What do you think? yes, good idea, i think it should be static (and takes a Proxy as parameter) to avoid unwanted overriding. Something like the following? http://cr.openjdk.java.net/~plevart/jdk9-dev/Proxy.invokeSuperDefaults/webrev.02/ Usage is even simpler with this API: public class Test { interface I1 { default void m() { System.out.println("default I1.m() called"); } } interface I2 { default void m() { System.out.println("default I2.m() called"); } } interface I12 extends I1, I2 { @Override void m(); } public static void main(String[] args) { InvocationHandler h = (proxy, method, params) -> { System.out.println("InvocationHandler called for: " + method); try { return Proxy.invokeSuper(proxy, method, params); } catch (InvocationTargetException e) { throw e.getCause(); } }; I1 i1 = (I1) Proxy.newProxyInstance( I1.class.getClassLoader(), new Class[]{I1.class}, h); i1.m(); I2 i2 = (I2) Proxy.newProxyInstance( I2.class.getClassLoader(), new Class[]{I2.class}, h); i2.m(); I12 i12 = (I12) Proxy.newProxyInstance( I12.class.getClassLoader(), new Class[]{I12.class}, h); i12.m(); } } Gives the following output: InvocationHandler called for: public default void Test$I1.m() default I1.m() called InvocationHandler called for: public default void Test$I2.m() default I2.m() called InvocationHandler called for: public abstract void Test$I12.m() Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at $Proxy2.m(Unknown Source) at Test.main(Test.java:49) Caused by: java.lang.IllegalAccessException: no such method: Test$I12.m()void/invokeSpecial at java.lang.invoke.MemberName.makeAccessException(java.base@9-internal/MemberName.java:928) at java.lang.invoke.MemberName$Factory.resolveOrFail(java.base@9-internal/MemberName.java:1064) at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(java.base@9-internal/MethodHandles.java:1692) at java.lang.invoke.MethodHandles$Lookup.findSpecial(java.base@9-internal/MethodHandles.java:1150) at java.lang.reflect.Proxy.invokeSuper(java.base@9-internal/Proxy.java:1151) at Test.lambda$main$0(Test.java:33) ... 2 more Caused by: java.lang.AbstractMethodError: Test$I12.m()V at java.lang.invoke.MethodHandleNatives.resolve(java.base@9-internal/Native Method) at java.lang.invoke.MemberName$Factory.resolve(java.base@9-internal/MemberName.java:1036) at java.lang.invoke.MemberName$Factory.resolveOrFail(java.base@9-internal/MemberName.java:1061) ... 6 more ...which is expected. You can't call the super abstract method. You have to resolve the Method object of a particular interface (I1 or I2) yourself in such case. I think this is a simple API that everyone could understand. Regards, Peter ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: proxy an interface and call a default method
On 06/02/2016 06:34 PM, fo...@univ-mlv.fr wrote: So perhaps, instead of providing a Proxy::findSuper method that returns a pre-bound MH, there could simply be a method like the following in the Proxy class: public final Object invokeSuper(Class interfaze, String methodName, MethodType methodType, Object ... args) { ... } What do you think? yes, good idea, i think it should be static (and takes a Proxy as parameter) to avoid unwanted overriding. Something like the following? http://cr.openjdk.java.net/~plevart/jdk9-dev/Proxy.invokeSuperDefaults/webrev.02/ Usage is even simpler with this API: public class Test { interface I1 { default void m() { System.out.println("default I1.m() called"); } } interface I2 { default void m() { System.out.println("default I2.m() called"); } } interface I12 extends I1, I2 { @Override void m(); } public static void main(String[] args) { InvocationHandler h = (proxy, method, params) -> { System.out.println("InvocationHandler called for: " + method); try { return Proxy.invokeSuper(proxy, method, params); } catch (InvocationTargetException e) { throw e.getCause(); } }; I1 i1 = (I1) Proxy.newProxyInstance( I1.class.getClassLoader(), new Class[]{I1.class}, h); i1.m(); I2 i2 = (I2) Proxy.newProxyInstance( I2.class.getClassLoader(), new Class[]{I2.class}, h); i2.m(); I12 i12 = (I12) Proxy.newProxyInstance( I12.class.getClassLoader(), new Class[]{I12.class}, h); i12.m(); } } Gives the following output: InvocationHandler called for: public default void Test$I1.m() default I1.m() called InvocationHandler called for: public default void Test$I2.m() default I2.m() called InvocationHandler called for: public abstract void Test$I12.m() Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at $Proxy2.m(Unknown Source) at Test.main(Test.java:49) Caused by: java.lang.IllegalAccessException: no such method: Test$I12.m()void/invokeSpecial at java.lang.invoke.MemberName.makeAccessException(java.base@9-internal/MemberName.java:928) at java.lang.invoke.MemberName$Factory.resolveOrFail(java.base@9-internal/MemberName.java:1064) at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(java.base@9-internal/MethodHandles.java:1692) at java.lang.invoke.MethodHandles$Lookup.findSpecial(java.base@9-internal/MethodHandles.java:1150) at java.lang.reflect.Proxy.invokeSuper(java.base@9-internal/Proxy.java:1151) at Test.lambda$main$0(Test.java:33) ... 2 more Caused by: java.lang.AbstractMethodError: Test$I12.m()V at java.lang.invoke.MethodHandleNatives.resolve(java.base@9-internal/Native Method) at java.lang.invoke.MemberName$Factory.resolve(java.base@9-internal/MemberName.java:1036) at java.lang.invoke.MemberName$Factory.resolveOrFail(java.base@9-internal/MemberName.java:1061) ... 6 more ...which is expected. You can't call the super abstract method. You have to resolve the Method object of a particular interface (I1 or I2) yourself in such case. I think this is a simple API that everyone could understand. Regards, Peter ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: proxy an interface and call a default method
- Mail original - > De: "Peter Levart"> À: fo...@univ-mlv.fr > Cc: "Da Vinci Machine Project" , "jochen > Theodorou" > Envoyé: Jeudi 2 Juin 2016 15:23:44 > Objet: Re: proxy an interface and call a default method > Hi Remi, Jochen, > On 06/02/2016 11:15 AM, fo...@univ-mlv.fr wrote: > > > > The solution could be for Proxy API to provide a MH that was already > > > > > bound to the Proxy instance. Such pre-bound MH could not be abused > > > > then. > > > > > independently of any security issue, it may be a good idea but doing a > > partial evaluation on a MH is not cheap. > > I created a prototype for this: > http://cr.openjdk.java.net/~plevart/jdk9-dev/Proxy.invokeSuperDefaults/webrev.01/ > Example usage is as follows: > public class Test { > interface I { > default void m() { > System.out.println("default I.m() called"); > } > } > public static void main(String[] args) { > InvocationHandler h = (proxy, method, params) -> { > System.out.println("InvocationHandler called for: " + method); > MethodHandle superM = ((Proxy) proxy).findSuper(I.class, "m", > MethodType.methodType(void.class)); > return superM.invokeWithArguments(params); > }; > I i = (I) Proxy.newProxyInstance( > I.class.getClassLoader(), new Class[]{I.class}, h); > i.m(); > } > } > It works, but in order for this to have adequate performance, caching would > have to be added. But caching a pre-bound MH would require caching on > per-proxy-instance basis, which would not be very efficient. So perhaps, > instead of providing a Proxy::findSuper method that returns a pre-bound MH, > there could simply be a method like the following in the Proxy class: > public final Object invokeSuper(Class interfaze, String methodName, > MethodType methodType, Object ... args) { ... } > What do you think? yes, good idea, i think it should be static (and takes a Proxy as parameter) to avoid unwanted overriding. > Regards, Peter Rémi ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: proxy an interface and call a default method
Hi Remi, Jochen, On 06/02/2016 11:15 AM, fo...@univ-mlv.fr wrote: >The solution could be for Proxy API to provide a MH that was already >bound to the Proxy instance. Such pre-bound MH could not be abused then. independently of any security issue, it may be a good idea but doing a partial evaluation on a MH is not cheap. I created a prototype for this: http://cr.openjdk.java.net/~plevart/jdk9-dev/Proxy.invokeSuperDefaults/webrev.01/ Example usage is as follows: public class Test { interface I { default void m() { System.out.println("default I.m() called"); } } public static void main(String[] args) { InvocationHandler h = (proxy, method, params) -> { System.out.println("InvocationHandler called for: " + method); MethodHandle superM = ((Proxy) proxy).findSuper(I.class, "m", MethodType.methodType(void.class)); return superM.invokeWithArguments(params); }; I i = (I) Proxy.newProxyInstance( I.class.getClassLoader(), new Class[]{I.class}, h); i.m(); } } It works, but in order for this to have adequate performance, caching would have to be added. But caching a pre-bound MH would require caching on per-proxy-instance basis, which would not be very efficient. So perhaps, instead of providing a Proxy::findSuper method that returns a pre-bound MH, there could simply be a method like the following in the Proxy class: public final Object invokeSuper(Class interfaze, String methodName, MethodType methodType, Object ... args) { ... } What do you think? Regards, Peter ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: proxy an interface and call a default method
- Mail original - > De: "Peter Levart"> À: "Remi Forax" , "Da Vinci Machine Project" > > Cc: "jochen Theodorou" > Envoyé: Jeudi 2 Juin 2016 10:26:48 > Objet: Re: proxy an interface and call a default method > > > > On 05/27/2016 01:40 PM, Remi Forax wrote: > > I don't see the issue if the lookup object represent the proxy class itself > > restricted to only access to public methods. > > > > Rémi > > I think there could be security issues. For example, let there be an > interface like: > > public interface Resource { > InputStream openStream() throws IOException; > > default byte[] getContent() throws IOException { > try (InputStream is = openStream()) { > return is.readAllBytes(); > } > } > } > > Then there might be an implementation that overrides both methods, like: > > public class SecuredResource implements Resource { > > @CallerSensitive > @Override > public InputStream openStream() throws IOException { > checkPermission(Reflection.getCallerClass()); > return openStreamImpl(); > } > > @CallerSensitive > @Override > public byte[] getContent() throws IOException { > checkPermission(Reflection.getCallerClass()); > try (InputStream is = openStreamImpl()) { > return is.readAllBytes(); > } > } > > private InputStream openStreamImpl() throws IOException { ... > ... > } > > > If Proxy API allowed access to a MH(invokespecial Resource::getContent), > then one could abuse such MH to circumvent access check in an instance > of SecuredResource by making it appear it was invoked from the Resource > class. > > I think that bytecode verifier does not allow such things and > SecuredResource can be considered perfectly safe in this respect. I dont think this code is safe, without any proxy, you can create a MethodHandle with findvirtual() on Resource::getContent and bypass the check on @CallerSensitive. I'm not a security guy, but IMO, you can not annotate an overridden method with @CallerSensitive without creating a security hole. > > The solution could be for Proxy API to provide a MH that was already > bound to the Proxy instance. Such pre-bound MH could not be abused then. independently of any security issue, it may be a good idea but doing a partial evaluation on a MH is not cheap. > > Regards, Peter Rémi > > > > > - Mail original - > >> De: "Peter Levart" > >> À: "Da Vinci Machine Project" , "jochen > >> Theodorou" > >> Envoyé: Vendredi 27 Mai 2016 12:50:34 > >> Objet: Re: proxy an interface and call a default method > >> > >> Hi, > >> > >> I think the main problem here is that by providing the InvocationHandler > >> with a Lookup that could provide "invokespecial" MHs for the proxy > >> interface(s) could be abused. Anyone can create a Proxy for any public > >> interface and supply its own InvocationHandler which could be used to > >> "steal" such Lookup object. > >> > >> There would have to be a way to restrict calling interface "super" > >> methods from InvocationHandler *INSTANCES* that are bound to particular > >> Proxy instances. > >> > >> Hm... > >> > >> Regards, Peter > >> > >> On 05/26/2016 08:20 AM, Jochen Theodorou wrote: > >>> Hi all, > >>> > >>> I am looking for a solution to the following problem... I have an > >>> interface and an object that is supposed to serve as implementation, > >>> but does not implement the interface. n methods of the interface will > >>> be redirected to the object, but in case of default methods I would > >>> like to have the implementation provided by the interface. I am > >>> looking especially for a solution without me generating classes at > >>> runtime by hand. > >>> > >>> Now there are several problems... I seem not to be able to invoke a > >>> default method by reflection. By MethodHandles I did something like this: > >>> > MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, > int.class). > newInstance(interfaceClass, MethodHandles.Lookup.PRIVATE). > unreflectSpecial(method, interfaceClass). > bindTo(receiver); > >>> where receiver is a dynamic proxy, method the Method of the default > >>> method, interfaceClass the Class of the interface with the default > >>> method. > >>> > >>> But I am calling a private constructor here, which is bad, plus the > >>> above procedure does no longer work on JDK9. > >>> > >>> So what am I supposed to do? change from a proxy to runtime generated > >>> classes and hope the best for classloaders and modules not getting in > >>> my way? > >>> > >>> bye Jochen > >>> ___ > >>> mlvm-dev mailing list > >>> mlvm-dev@openjdk.java.net > >>>
Re: proxy an interface and call a default method
On 05/27/2016 01:40 PM, Remi Forax wrote: I don't see the issue if the lookup object represent the proxy class itself restricted to only access to public methods. Rémi I think there could be security issues. For example, let there be an interface like: public interface Resource { InputStream openStream() throws IOException; default byte[] getContent() throws IOException { try (InputStream is = openStream()) { return is.readAllBytes(); } } } Then there might be an implementation that overrides both methods, like: public class SecuredResource implements Resource { @CallerSensitive @Override public InputStream openStream() throws IOException { checkPermission(Reflection.getCallerClass()); return openStreamImpl(); } @CallerSensitive @Override public byte[] getContent() throws IOException { checkPermission(Reflection.getCallerClass()); try (InputStream is = openStreamImpl()) { return is.readAllBytes(); } } private InputStream openStreamImpl() throws IOException { ... ... } If Proxy API allowed access to a MH(invokespecial Resource::getContent), then one could abuse such MH to circumvent access check in an instance of SecuredResource by making it appear it was invoked from the Resource class. I think that bytecode verifier does not allow such things and SecuredResource can be considered perfectly safe in this respect. The solution could be for Proxy API to provide a MH that was already bound to the Proxy instance. Such pre-bound MH could not be abused then. Regards, Peter - Mail original - De: "Peter Levart"À: "Da Vinci Machine Project" , "jochen Theodorou" Envoyé: Vendredi 27 Mai 2016 12:50:34 Objet: Re: proxy an interface and call a default method Hi, I think the main problem here is that by providing the InvocationHandler with a Lookup that could provide "invokespecial" MHs for the proxy interface(s) could be abused. Anyone can create a Proxy for any public interface and supply its own InvocationHandler which could be used to "steal" such Lookup object. There would have to be a way to restrict calling interface "super" methods from InvocationHandler *INSTANCES* that are bound to particular Proxy instances. Hm... Regards, Peter On 05/26/2016 08:20 AM, Jochen Theodorou wrote: Hi all, I am looking for a solution to the following problem... I have an interface and an object that is supposed to serve as implementation, but does not implement the interface. n methods of the interface will be redirected to the object, but in case of default methods I would like to have the implementation provided by the interface. I am looking especially for a solution without me generating classes at runtime by hand. Now there are several problems... I seem not to be able to invoke a default method by reflection. By MethodHandles I did something like this: MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class). newInstance(interfaceClass, MethodHandles.Lookup.PRIVATE). unreflectSpecial(method, interfaceClass). bindTo(receiver); where receiver is a dynamic proxy, method the Method of the default method, interfaceClass the Class of the interface with the default method. But I am calling a private constructor here, which is bad, plus the above procedure does no longer work on JDK9. So what am I supposed to do? change from a proxy to runtime generated classes and hope the best for classloaders and modules not getting in my way? bye Jochen ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: proxy an interface and call a default method
I don't see the issue if the lookup object represent the proxy class itself restricted to only access to public methods. Rémi - Mail original - > De: "Peter Levart"> À: "Da Vinci Machine Project" , "jochen Theodorou" > > Envoyé: Vendredi 27 Mai 2016 12:50:34 > Objet: Re: proxy an interface and call a default method > > Hi, > > I think the main problem here is that by providing the InvocationHandler > with a Lookup that could provide "invokespecial" MHs for the proxy > interface(s) could be abused. Anyone can create a Proxy for any public > interface and supply its own InvocationHandler which could be used to > "steal" such Lookup object. > > There would have to be a way to restrict calling interface "super" > methods from InvocationHandler *INSTANCES* that are bound to particular > Proxy instances. > > Hm... > > Regards, Peter > > On 05/26/2016 08:20 AM, Jochen Theodorou wrote: > > Hi all, > > > > I am looking for a solution to the following problem... I have an > > interface and an object that is supposed to serve as implementation, > > but does not implement the interface. n methods of the interface will > > be redirected to the object, but in case of default methods I would > > like to have the implementation provided by the interface. I am > > looking especially for a solution without me generating classes at > > runtime by hand. > > > > Now there are several problems... I seem not to be able to invoke a > > default method by reflection. By MethodHandles I did something like this: > > > >> MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, > >> int.class). > >> newInstance(interfaceClass, MethodHandles.Lookup.PRIVATE). > >> unreflectSpecial(method, interfaceClass). > >> bindTo(receiver); > > > > where receiver is a dynamic proxy, method the Method of the default > > method, interfaceClass the Class of the interface with the default > > method. > > > > But I am calling a private constructor here, which is bad, plus the > > above procedure does no longer work on JDK9. > > > > So what am I supposed to do? change from a proxy to runtime generated > > classes and hope the best for classloaders and modules not getting in > > my way? > > > > bye Jochen > > ___ > > mlvm-dev mailing list > > mlvm-dev@openjdk.java.net > > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > > ___ > mlvm-dev mailing list > mlvm-dev@openjdk.java.net > http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev > ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
Re: proxy an interface and call a default method
Hi, I think the main problem here is that by providing the InvocationHandler with a Lookup that could provide "invokespecial" MHs for the proxy interface(s) could be abused. Anyone can create a Proxy for any public interface and supply its own InvocationHandler which could be used to "steal" such Lookup object. There would have to be a way to restrict calling interface "super" methods from InvocationHandler *INSTANCES* that are bound to particular Proxy instances. Hm... Regards, Peter On 05/26/2016 08:20 AM, Jochen Theodorou wrote: Hi all, I am looking for a solution to the following problem... I have an interface and an object that is supposed to serve as implementation, but does not implement the interface. n methods of the interface will be redirected to the object, but in case of default methods I would like to have the implementation provided by the interface. I am looking especially for a solution without me generating classes at runtime by hand. Now there are several problems... I seem not to be able to invoke a default method by reflection. By MethodHandles I did something like this: MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class). newInstance(interfaceClass, MethodHandles.Lookup.PRIVATE). unreflectSpecial(method, interfaceClass). bindTo(receiver); where receiver is a dynamic proxy, method the Method of the default method, interfaceClass the Class of the interface with the default method. But I am calling a private constructor here, which is bad, plus the above procedure does no longer work on JDK9. So what am I supposed to do? change from a proxy to runtime generated classes and hope the best for classloaders and modules not getting in my way? bye Jochen ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev ___ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev