What does the sun.reflect.CallerSensitive annotation mean?
According to the JEP I linked to in the comments (also here),
A caller-sensitive method varies its behavior according to the class of its immediate caller. It discovers its caller’s class by invoking the
sun.reflect.Reflection.getCallerClass
method.
If you look at the implementation of Class#forName(String)
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true,
ClassLoader.getClassLoader(Reflection.getCallerClass()));
}
, you notice that it is using Reflection.getCallerClass()
. If we look at that method
Returns the class of the caller of the method calling this method, ignoring frames associated with
java.lang.reflect.Method.invoke()
and its implementation.
@CallerSensitive
public static native Class getCallerClass();
The problem, it seems, before this JEP, was that if the caller sensitive method was called through reflection instead of directly, there had to be a complex process to identify what the actual calling class was. This was problematic if the method was invoked through reflection. A simpler process was proposed (and introduced) with @CallerSensitive
.
Basically, the @CallerSensitive
annotation is used by the JVM
The JVM will track this annotation and, optionally, enforce the invariant that the
sun.reflect.Reflection.getCallerClass
method can only report the caller of a method when that method is marked with this annotation.
From jdk.internal.reflect.CallerSensitive
A method annotated @CallerSensitive is sensitive to its calling class, via Reflection.getCallerClass or via some equivalent.
The equivalent would be java.lang.StackWalker.getCallerClass
since Java SE 9.
This is effectively the security model of Java versions 1.0 and 1.1, which implemented a sort of pauper's linker checking. It's a coherent approach except for anything related to reflection but is exteremely fragile. The more restrictive Java 2 security model, on the other hand, is magic and doesn't show its workings.
@CallerSensitive
methods alter behaviour depending upon the class that called them. This is always surprising, but then so is the Java 2 stack-inspection security model. To make matters worse, these method calls are particularly useful for classes that are working on behalf of their caller, so the context is wrong anyway.
The Secure Coding Guidelines for Java SE covers this area.
- Guideline 9-8 / ACCESS-8: Safely invoke standard APIs that bypass SecurityManager checks depending on the immediate caller's class loader
- Guideline 9-9 / ACCESS-9: Safely invoke standard APIs that perform tasks using the immediate caller's class loader instance
- Guideline 9-10 / ACCESS-10: Be aware of standard APIs that perform Java language access checks against the immediate caller
- Guideline 9-11 / ACCESS-11: Be aware java.lang.reflect.Method.invoke is ignored for checking the immediate caller
- Guideline 9-12 / ACCESS-12: Avoid using caller-sensitive method names in interface classes
The introduction of modules in Java SE 9 has meant that some of the details have changed.
Additionally if the @CallerSensitive
method is called with Method.invoke
some of the stack frames are ignored by getCallerClass
. Internally the JDK uses a "trampoline" ClassLoader
to act as a benign dummy caller. java.lang.invoke.MethodHandle
copies problems of Method.invoke
. The AccessController.doPrivileged
methods are also problematic with the consequences of the specification being surprising.
JEP 176: Mechanical Checking of Caller-Sensitive Methods deals with the particular @CallerSensitive
jdk-internal annotation. The method lists in the Guidelines were generated by a FindBugs plug-in but then manually updated.