groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject Re: trySetAccessible for Java 9
Date Mon, 10 Jul 2017 00:26:43 GMT
On 09.07.2017 13:13, Uwe Schindler wrote:
> Hi,
> 
> thanks for the insight. I was just not sure where this synthetic class 
> name came from.
> 
> I think we should ask on the Jigsaw mailing list if the warning was 
> intended to be also printed by the trySetAccessible call. IMHO, 
> trySetAccessible is a new API, so it should **not** grant access nor 
> print a warning. The Jigsaw kill switch should have no effect on 
> trySetAccessible! In contrast, setAccessible should behave as it does 
> with the Jigsaw kill switch enabled.

maybe they did it wrong, since they changed the kill switch suddenly.

> Nevertheless, I’d change the code in the following way: Instead of 
> trySetAccessible method handle, use a methodhandle to get the Module 
> instance of the Groovy runtime (fetch it once in the static initializer 
> -- should be the unnamed module, but we should be flexible here) and 
> when trying to make everything accessible in a class, use the same 
> methodhandle to get the module, too. If the module if different, don’t 
> try to make anything accessible at all and just return with empty array. 
> In the future we may try improve the whole thing my looking into the 
> module properties (“open” packages), but as a quick fix this is fine.

well... let us assume you have a class

class IAmInJavaBase {
   final protected void callMe()
}

in java.base and this

class GroovyWithModules extends IAmInJavaBase {
   void foo(){callMe()}
}

The Groovy runtime will no longer be allowed to call "callMe", because 
while the unnamed module reads java.base, it does not make java.base 
automatically an open module. And even if IAmInJavaBase is in an 
exported package, that does not include "callMe"

The two ways to make this call work is by using the Lookup object 
provided by GroovyWithModules and a direct method call. Even if you get 
that right, you still have to handle inner classes and Closures. 
(Technically you can do this with reflection as well, but then the 
invokeMethod has to come from GroovyWithModules directly)

Now if you stop trying to make things accessible and just return an 
empty array, then "callMe" will not exist anymore. That means, that even 
in indy, where you have this lookup object, you will get a 
MissingMethodException.

If you go with the approach of reacting to AccessibleObject.canAccess 
returning true... I would be very surprised to see canAccess returning 
true for that method.

the major pain with the central invoker simply is, that if X can access 
foo and Y cannot access foo, you have trouble to make a system in which 
both are allowed to make their call... especially if you do not know by 
100% who the original caller actually is.

[...]
> Finally I have the question: Is it really needed to keep trying to make 
> everything accessible by default in Groovy 3 ???

The big problem is giving up the central invoker pattern completely. It 
also means dragging Lookup instances through the whole MOP to finally 
reach the place of invocation... or to change the whole MOP to return 
something you can invoke.

My original plan for MOP2 was actually trying to change the MOP to 
always return something you can then invoke. But...

class GroovyWithModules extends IAmInJavaBase {
   void foo(){
     def cl = new Helper().build()
     cl.setDelegate(this)
     cl.call()
   }
}

class Helper {
   def build() {
     return { callMe () }
   }
}

new GroovyWithModules().foo()

This code works in Groovy today, but with modules... So even though I do 
let build return something that can call callMe() I still have to give 
it the rights to do so. So either I transport the Lookup object through 
the whole MOP and let it for example return a MethodHandle, or I create 
another intermediate layer here that I can control from the caller and 
that then will produce the MethodHandle with the appropriate Lookup 
object. So I do have to at least combine the two approaches now.

And frankly, in the code above I use Helper just as an demonstration of 
what the runtime would have to do. If I actually want to get the above 
working I am pretty screwed. In { callMe () } the best lookup object I 
can automatically use is the one from Helper, and that one is not having 
access.

I could introduce something like:

class Helper {
   def build(x) {
     return { inTheNameOf(x) {callMe ()} }
   }
}

A where x is actually a GroovyWithModules instance with very special 
logic for inTheNameOf, which would basically try to somehow get the 
Lookup object with enough rights from x to be able to do the call. This 
looks majorly awkward and you actually rip open all the holes, the 
module system is supposed to keep under the covers. In the end the whole 
concept of setting a delegate is now broken for the module system. 
Because in the end, each of our Closures are specialized central 
invoker. And something like x."$foo"() takes the specialization away 
completely. Since central invoker do not work properly anymore in JDK9, 
Closures will also produce trouble in some cases.

> Maybe you should break 
> backwards compatibility and no longer do this by default. 

You know, if breaking the API would be our only problem here, it 
wouldn't be a big deal. Having to overthrow basic concepts of the 
language is the kind of backwards compatibility break we are talking 
about here.

> This was IMHO 
> a mis-design of the Groovy language from the beginning.

It was the way to do it back in 2004 with a security manager. And the 
security manager mechanism almost forced this structure upon you.

> This is also a 
> security issue, as every groovy module can corrupt the whole JVM. This 
> is also one reason why Elasticsearch moved to their own scripting 
> language, as the cowboy “setAccessible” everywhere is a serious security 
> issue!

Yes, they do not know how to use a security manager or simply do not 
want to bother with one.

bye Jochen

Mime
View raw message