Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception in StringConcatFactory - Java 9

Tags:

java

java-9

While learning java9 StringConcatFactory class I am unable to understand why following code with MethodHandles.publicLookup() throws StringConcatException exception while if MethodHandles.lookup() is used everything is working fine.

As per java docs of lookup:

"lookup - Represents a lookup context with the accessibility privileges of the caller"

StringConcatFactory.makeConcat(MethodHandles.publicLookup(),
"abc",MethodType.methodType(String.class));//Exception Here


StringConcatFactory.makeConcat(MethodHandles.lookup(), 
"abc", MethodType.methodType(String.class)); //Working fine

I am not sure where I am mistaken? Please help me understand this behavior.

like image 986
Sachin Sachdeva Avatar asked Sep 05 '17 07:09

Sachin Sachdeva


3 Answers

The javadoc for makeConcat says about the first parameter:

lookup Represents a lookup context with the accessibility privileges of the caller

The lookup context returned by publicLookup does not have those privileges.

Even if you concatenate nothing, the exception will still be thrown:

MethodType concatType = MethodType.methodType(String.class); // No arguments, returns String
StringConcatFactory.makeConcat(MethodHandles.publicLookup(), "abc", concatType); // Exception

Because the access privileges of the context are checked in StringConcatFactory#doStringConcat:

if ((lookup.lookupModes() & MethodHandles.Lookup.PRIVATE) == 0) {
    throw new StringConcatException("Invalid caller: " +
            lookup.lookupClass().getName());
}

The context needs a private lookup mode, and a publicLookup does not have it:

System.out.println((MethodHandles.publicLookup().lookupModes()
    & MethodHandles.Lookup.PRIVATE) != 0); // false
System.out.println((MethodHandles.lookup().lookupModes()
    & MethodHandles.Lookup.PRIVATE) != 0); // true
like image 175
Jorn Vernee Avatar answered Sep 25 '22 23:09

Jorn Vernee


The Javadoc for publicLookup() says:

Returns a lookup object which is trusted minimally.

versus lookup():

Returns a lookup object with full capabilities to emulate all supported bytecode behaviors of the caller. These capabilities include private access to the caller. Factory methods on the lookup object can create direct method handles for any member that the caller has access to via bytecodes, including protected and private fields and methods. This lookup object is a capability which may be delegated to trusted agents.

And the Javadoc for makeConcat() finally says:

throws StringConcatException - If any of the linkage invariants described here are violated.

Given the fact that the question does not contain any more details, the most likely answer is: you have some sort of "permission" problem here. Maybe you try to "concat" something that simply isn't available when using "minimal trust".

like image 33
GhostCat Avatar answered Sep 24 '22 23:09

GhostCat


The primary reason as in your case when a publicLookup :

StringConcatFactory.makeConcat(MethodHandles.publicLookup(), "abc", MethodType.methodType(String.class));

can throw a StringConcatException while on the other hand, the lookup

StringConcatFactory.makeConcat(MethodHandles.lookup(), "abc", MethodType.methodType(String.class));

would work fine is when the method handle created are used to access private members of a class of a private class of a package.

As stated in the Javadoc of publicLookup linked by @GhostCat as well

publicLookup => PUBLIC_LOOKUP => (PUBLIC|UNCONDITIONAL) modes

Returns a lookup object which is trusted minimally. The lookup has the PUBLIC and UNCONDITIONAL modes. It can only be used to create method handles to public members of public classes in packages that are exported unconditionally.

while for a lookup

lookup => (lookupClass => Reflection.getCallerClass, FULL_POWER_MODES  => (ALL_MODES & ~UNCONDITIONAL))

Returns a lookup object with full capabilities to emulate all supported bytecode behaviors of the caller. These capabilities include private access to the caller. Factory methods on the lookup object can create direct method handles for any member that the caller has access to via bytecodes, including protected and private fields and methods. This lookup object is a capability which may be delegated to trusted agents.

Do not store it in place where untrusted code can access it. This method is caller sensitive, which means that it may return different values to different callers.

For any given caller class C, the lookup object returned by this call has equivalent capabilities to any lookup object supplied by the JVM to the bootstrap method of an invokedynamic instruction executing in the same caller class C.

like image 27
Naman Avatar answered Sep 25 '22 23:09

Naman