Okay, but I don't think @CallerSensitive is necessary to prevent MethodHandles 
from spoofing caller classes. I'll admit I don't know very much about 
MethodHandle, what it does, or how its invocation methods are different from 
Method.invoke(). In the code that I copied into this email from jvm.cpp last 
night, the third frame (frame #2) will always be returned unless it is one 
ignored by the security stack walk. @CallerSensitive doesn't come in to play 
here.

Nick

On Jul 31, 2013, at 2:36 AM, Peter Levart wrote:

> Hi Nick,
> 
> The @CallerSensitive annotation is an annotation that prevents some other 
> infrastructure, namely the MethodHandles, to "spoof" caller classes.
> 
> Try this:
> 
>         MethodHandles.Lookup lookup = MethodHandles.lookup().in(Object.class);
>         MethodHandle mh = lookup.findStatic(Class.class, "forName", 
> MethodType.methodType(Class.class, String.class));
> 
> ...you won't be able to pretend that you are the j.l.Object that is calling 
> method Class.forName(String)...
> 
> The annotation might have (or will have?) other effects like making sure some 
> infrastructure-inserted frames are hidden-away just for @CallerSensitive 
> methods which might be less optimal and not needed for normal methods.
> 
> 
> Regards, Peter
> 
> On 07/31/2013 01:11 AM, Nick Williams wrote:
>> Quick question for those of you that know anything about @CallerSensitive...
>> 
>> After looking at the code and experimenting some, I've discovered that 
>> getCallerClass() doesn't actually keep going until it finds the first method 
>> without @CallerSensitive. It only returns the caller of the caller. So, for 
>> example:
>> 
>> Stack 1
>> @CallerSensitive Reflection.getCallerClass()
>> @CallerSensitive MyClass1.method1();
>> MyClass2.method2();
>> 
>> In this case, getCallerClass() returns MyClass2.class. BUT:
>> 
>> Stack 2
>> @CallerSensitive Reflection.getCallerClass()
>> @CallerSensitive MyClass1.method1();
>> @CallerSensitive MyClass2.method2();
>> MyClass3.method3();
>> 
>> In this case, getCallerClass() STILL returns MyClass2.class. Based on the 
>> plain-language meaning of @CallerSensitive, I would expect getCallerClass() 
>> to return MyClass3.class in the second case. But, indeed, the JavaDoc for 
>> Reflection.getCallerClass() says: "Returns the class of the caller of the 
>> method calling this method." So, then, what's the point of @CallerSensitive? 
>> Looking at the code:
>> 
>>    vframeStream vfst(thread);
>>    // Cf. LibraryCallKit::inline_native_Reflection_getCallerClass
>>    for (int n = 0; !vfst.at_end(); vfst.security_next(), n++) {
>>      Method* m = vfst.method();
>>      assert(m != NULL, "sanity");
>>      switch (n) {
>>      case 0:
>>        // This must only be called from Reflection.getCallerClass
>>        if (m->intrinsic_id() != vmIntrinsics::_getCallerClass) {
>>          THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), 
>> "JVM_GetCallerClass must only be called from Reflection.getCallerClass");
>>        }
>>        // fall-through
>>      case 1:
>>        // Frame 0 and 1 must be caller sensitive.
>>        if (!m->caller_sensitive()) {
>>          THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), 
>> err_msg("CallerSensitive annotation expected at frame %d", n));
>>        }
>>        break;
>>      default:
>>        if (!m->is_ignored_by_security_stack_walk()) {
>>          // We have reached the desired frame; return the holder class.
>>          return (jclass) JNIHandles::make_local(env, 
>> m->method_holder()->java_mirror());
>>        }
>>        break;
>>      }
>>    }
>> 
>> It seems to me that @CallerSensitive is completely pointless. This is ALWAYS 
>> going to return the first non-reflection frame after frame 1, regardless of 
>> @CallerSensitive. If @CallerSensitive were really supposed to have an actual 
>> purpose, it would seem to me that the last part should be this:
>> 
>>        if (!m->is_ignored_by_security_stack_walk() && 
>> !m->caller_sensitive()) {
>>          // We have reached the desired frame; return the holder class.
>>          return (jclass) JNIHandles::make_local(env, 
>> m->method_holder()->java_mirror());
>>        }
>> 
>> Am I completely missing the point here? I just don't see a reason for 
>> @CallerSensitive. The code could do the exact same thing it currently is 
>> without @CallerSensitive (except for enforcing that frame 1 is 
>> @CallerSensitive, which really isn't necessary if you aren't using it in 
>> further frames).
>> 
>> Thoughts?
>> 
>> Nick
>> 
>> On Jul 30, 2013, at 10:33 AM, Jochen Theodorou wrote:
>> 
>>> Am 30.07.2013 16:16, schrieb Peter Levart:
>>>> On 07/30/2013 03:19 PM, Jochen Theodorou wrote:
>>>>> Am 30.07.2013 14:17, schrieb Peter Levart:
>>>>> [...]
>>>>>> So what would give Groovy or other language runtimes headaches when all
>>>>>> there was was a parameter-less getCallerClass() API? Aren't the
>>>>>> intermediate frames inserted by those runtimes controlled by the
>>>>>> runtimes? Couldn't the "surface" runtime-inserted methods capture the
>>>>>> caller and pass it down? I guess the problem is supporting calling the
>>>>>> caller-sensitive methods like Class.forName(String) and such which don't
>>>>>> have the overloaded variant taking caller Class or ClassLoader as an
>>>>>> argument...
>>>>> Speaking for Groovy...
>>>>> those intermediate frames are runtime controlled, yes, but passing down
>>>>> the caller class is exactly the problem. Imagine I would suggest that
>>>>> each and every method definition in Java automatically gets an
>>>>> additional parameter for the caller class, just to have access to it
>>>>> inside the method. You would not accept that for Java, would you? And so
>>>>> we cannot accept that for Groovy if we want to keep integration with
>>>>> Java...
>>>> Are you talking about internal Groovy implementation (the
>>>> runtime-inserted methods) or the publicly visible API?
>>> that's the problem, it is a mix, some internal, other not. We are going to 
>>> change that in Groovy 3
>>> 
>>>> One solution for
>>>> internal implementation of Groovy could be (speaking by heart since I
>>>> don't know the internals of Groovy) for the "surface" public API method
>>>> which doesn't have to have the special caller parameter, to capture the
>>>> caller with getCallerClass() parameterless API (possibly enclosed with a
>>>> quick check confirming that it might actually be needed) and bind it to
>>>> a ThreadLocal, then use this ThreadLocal down at the end...
>>> confirming that it might actually be needed is a problem. In the old 
>>> fallback path we don't know what we call until after we are deep in runtime 
>>> code, and there it is too late. In the other paths we could mark those 
>>> methods in a @CallerSensitive style and do it in that case only.
>>> 
>>>>> and the good integration with Java is one of the key points of
>>>>> Groovy. Even if we make something like that @CallerSensitive and add the
>>>>> parameter only in those cases, we break being able to override methods.
>>>> I guess I don't know every Groovy need to obtain the caller class. I
>>>> thought the problem was to support calling caller-sensitive methods in
>>>> Java API (like Class.forName(String)) from within Groovy code, where
>>>> there are runtime-inserted frames between the "call-site" and the target
>>>> method. Are there any other needs?
>>> ok, there is a misunderstanding...
>>> 
>>> if we call a Java implemented method from Groovy, which is using 
>>> getCallerClass() it may or may not work. In general this does not work and 
>>> our problem is not about that at all. With the change to let 
>>> getCallerClass() ignore some reflective frames it will work actually better 
>>> as long as we use our custom callsite caching implementation, it will not 
>>> work if indy is used or the fallback path.
>>> 
>>> To be able to call a method Class#forName(String), we need to "replace" it 
>>> with an implementation of our own, which we do with an approach similar to 
>>> extension methods (only that ours can hide existing implementation methods 
>>> for groovy). And in there we need to get to the caller class
>>> 
>>> Our problem though is @Grab which is an annotation to add elements to the 
>>> classpath while running a script.
>>> 
>>>>> Plus, before Groovy3 is not done we have to support several call paths.
>>>>> And the oldest one, which is still a fallback, does not support
>>>>> transporting the caller class through the runtime layers at all.
>>>>> Changing here is a breaking change.
>>>> Could you describe those call-paths? Examples of Groovy code and to what
>>>> it gets translated (equivalent Java code at call site) with a brief
>>>> description of what each intermediate layer (between the call-site and
>>>> the target method) does and at which point the caller class is extracted...
>>> the code generated at the call site depends on several factors actually... 
>>> The call site code itself is usually not very informative
>>> 
>>> I start with Groovy 1.0, since that is basically the fallback path. Here 
>>> this.foo() translates more or less to
>>> ScriptBytecodeAdapter.invokeMethod0(staticCallerClass, this,"foo")
>>> which basically does this.getMetaClass().invokeMethod(staticCallerClass, 
>>> this, "foo"). The problem is that the meta class might be user supplied and 
>>> the code executed in invokeMethod as well. The invocation is then finally 
>>> done by reflection. That means we have frames from ScriptBytecodeAdapter, 
>>> from the meta class, as well as maybe frames from a custom meta class and 
>>> reflection frames. At the level of ScriptBytecodeAdapter there is a means 
>>> of transporting the caller class, but that is the static one. Once there is 
>>> a subclass, this information is different from what is needed here and it 
>>> cannot simply be exchanged. Even if the bytecode adapter is changed, we 
>>> cannot change the public API for MetaClass#invokeMethod now. And then the 
>>> information would be lost.
>>> 
>>> In later versions of Groovy (since 1.6) we introduced a custom call site 
>>> caching technique, which uses runtime generated classes to create a helper 
>>> class per call site and is then used for invocation. At the callsite we 
>>> basically have something like callsiteArray[i].invoke(..). Here again the 
>>> staticCallerClass can be found. In this version we are able to "get" the 
>>> method we want to invoke, before invoking it (bypassing 
>>> MetaClass#invokeMethod). But to be able to get the method, certain 
>>> conditions have to be met (like no user supplied meta class). If they are 
>>> not met, then we do basically the same path as in 1.0, only that we don't 
>>> use ScriptBytecodeAdapter. Instead We use our CallSite class as entrance 
>>> point, which then makes the call to the meta class. In the "efficent" case 
>>> we have now frames from the callsite handling code between the callsite and 
>>> the target method only. This includes reflection in the first 
>>> instantiation, later the generated class is used so it reduces to two frame
>>> s of which one is the Callsite entrance point, the other a frame form the 
>>> generated method. In the fallback case we have frames from the callsite 
>>> handling code, plus meta class code, plus reflection of course. Again the 
>>> fallback case prevents us from transporting the caller information to the 
>>> target method. If we ignore the fallback case, then we could here maybe use 
>>> the Threadlocal information. It will require a new callsite interface for 
>>> the bytecode though, meaning this code will not work for precompiled grovvy 
>>> of older version, excluding from getting into Groovy 2.1.x, since it would 
>>> be a breaking change. The earliest version for that would be Groovy 2.2.0, 
>>> which is almost in RC now. Effectively it would mean we would have to do a 
>>> 2.3.0 very soon after most probably.
>>> 
>>> In Groovy 2 we added an indy implementation, which replaces the callsite 
>>> caching code.  At the callsite we have here basically invokedynamic "foo" 
>>> with IndyInterface#bootstrap. bootstrap will first introduce a target for 
>>> IndyInterface#selectMethod, since I need the runtime types instead of the 
>>> static ones. The static caller class information is here part of the 
>>> bootstrap method as Lookup object, added by invokedynamic itself. After 
>>> selectMethod is done we have an initial invocation using invokeExact and 
>>> later invocations by the handle stored in the callsite. Of course the same 
>>> conditions as for the callsite caching above have to be met, meaning the 
>>> fallback path might appear. That makes initially one IndyInterface frame, 
>>> then invokedynamic and lambda related frames, then optionally the traget 
>>> method, or in the fallback case the meta class frames plus reflection
>>> 
>>> 
>>> bye Jochen
>>> 
>>> -- 
>>> Jochen "blackdrag" Theodorou - Groovy Project Tech Lead
>>> blog: http://blackdragsview.blogspot.com/
>>> german groovy discussion newsgroup: de.comp.lang.misc
>>> For Groovy programming sources visit http://groovy-lang.org
>>> 
> 

Reply via email to