-
Notifications
You must be signed in to change notification settings - Fork 738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check module visibility in method handles #1801
Check module visibility in method handles #1801
Conversation
The PR only adds this check to |
@dan The personal build has nearly finished and shows no errors so far. Would you kindly run a Jenkins sanity build? |
@@ -47,7 +47,7 @@ | |||
import com.ibm.oti.vm.VM; | |||
import com.ibm.oti.vm.VMLangAccess; | |||
|
|||
/*[IF Sidecar19-SE] | |||
/*[IF Sidecar19-SE]*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To reduce the syntax errors when editing in the new code in Eclipse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't that just move the syntax error from 9 to 8?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No: this change eliminates most of the syntax errors in the unprocessed code.
@@ -634,14 +636,26 @@ public MethodHandle findStatic(Class<?> clazz, String methodName, MethodType typ | |||
* @param methodName - the name of the method | |||
* @param type - the type of the method | |||
* @return a MethodHandle that will do virtual dispatch on the first argument | |||
* @throws IllegalAccessException - if method is static or access is refused | |||
* @throws IllegalAccessException - if method is static or access is refused or clazz's package is not exported to the current module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This javadoc will be generated for both 8 & 9+. Module should only be mentioned for 9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix.
@@ -634,14 +636,26 @@ public MethodHandle findStatic(Class<?> clazz, String methodName, MethodType typ | |||
* @param methodName - the name of the method | |||
* @param type - the type of the method | |||
* @return a MethodHandle that will do virtual dispatch on the first argument | |||
* @throws IllegalAccessException - if method is static or access is refused | |||
* @throws IllegalAccessException - if method is static or access is refused or clazz's package is not exported to the current module | |||
* @throws IllegalAccessError - if the type's packages are not exported to the current module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
module mentioned in 8
* @throws NullPointerException - if clazz, methodName or type is null | ||
* @throws NoSuchMethodException - if clazz has no virtual method named methodName with signature matching type | ||
* @throws SecurityException - if any installed SecurityManager denies access to the method | ||
*/ | ||
public MethodHandle findVirtual(Class<?> clazz, String methodName, MethodType type) throws IllegalAccessException, NoSuchMethodException { | ||
nullCheck(clazz, methodName, type); | ||
|
||
/*[IF Sidecar19-SE]*/ | ||
if (INTERNAL_PRIVILEGED != accessMode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be added to checkAccess()
?
Possibly. We don't have tests for these yet. |
1682dda
to
b8a104d
Compare
Working on tests for those. |
MethodType type = handle.type(); | ||
Module accessModule = accessClass.getModule(); | ||
checkClassModuleVisibility(accessModule, targetClass, false); | ||
checkClassModuleVisibility(accessModule, type.returnType, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two calls to checkClassModuleVisibility
, one setting throwError
to false while the other says true. Which is intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The throwable depends on the context. If the target class is not visible, we need to throw an IllegalAccessException. If the parameter or return types are not visible, we need to throw a IllegalAccessError.
/*[MSG "K0664", "{0} is not in an exported package"]*/ | ||
String message = Msg.getString("K0664", targetClass.getPackageName()); //$NON-NLS-1$ | ||
if (throwError) { | ||
throw new IllegalAccessError(message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likely better to only throw one exception and let the code that needs the Error wrap the Exception.
@@ -1160,6 +1160,7 @@ K0660="Internal error while obtaining private constructor." | |||
K0661="Internal error while obtaining GcInfo instance." | |||
K0662="maxDepth must not be negative." | |||
K0663="Invalid or unsupported dump agent option, cannot be triggered." | |||
K0664="{0} is not in an exported package" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no existing message that can be reused?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Fixed.
Module accessModule = accessClass.getModule(); | ||
checkClassModuleVisibility(accessModule, targetClass, false); | ||
checkClassModuleVisibility(accessModule, type.returnType, true); | ||
for (Class<?> c: type.parameterArray()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type.parameterArray()
allocates a new array - since this code is in the j.l.i package and we know it won't modify the array, better to use type.arguments
directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay.
* @throws IllegalAccessError thrown if throwError is true | ||
* @throws IllegalAccessException thrown if throwError is false | ||
*/ | ||
static void checkClassModuleVisibility(Module accessModule, Class<?> targetClass, boolean throwError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put the throw clauses on the same line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay.
if (!Objects.equals(accessModule, targetModule) | ||
&& !(targetModule.isExported(targetClass.getPackageName(), accessModule) | ||
&& accessModule.canRead(targetModule))) { | ||
/*[MSG "K0664", "{0} is not in an exported package"]*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the two modules to this message? It will be easier for a user to resolve an access failure if they get the module info in the exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
static void checkClassModuleVisibility(Module accessModule, Class<?> targetClass, boolean throwError) | ||
throws IllegalAccessError, IllegalAccessException { | ||
Module targetModule = targetClass.getModule(); | ||
if (!Objects.equals(accessModule, targetModule) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rewrite this as positive conditions?
b8a104d
to
1ea8a4b
Compare
Passes designer tests. Will run a larger regression suite tomorrow. |
JCL tests pass. @DanHeidinga or @pshipton could you take another look at the code? |
checkClassModuleVisibility(accessModule, c); | ||
} | ||
} catch (IllegalAccessException e) { | ||
throw new IllegalAccessError(e.getMessage()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better to chain the exceptions by setting the IllegalAccessException as the cause - either by initCause()
or through an appropriate constructor - so the original stack trace is preserved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is used a lot of places. Is IllegalAccessError expected by the callers? Wouldn't it be more consistent to have this function throw IAException and only callers that expect IAError to do the transformation?
/* The following access checking is for a normal class (non-member class) */ | ||
|
||
/* The following access checking is for a normal class (non-member class) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment applies to the else if
block, if it applies to anything at all, and should have kept its original indentation
* @param type - the type of the method | ||
* @return a MethodHandle that will do virtual dispatch on the first argument | ||
* @throws IllegalAccessException - if method is static or access is refused or clazz's package is not exported to the current module | ||
* @throws IllegalAccessError - if the type's packages are not exported to the current module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has the RI thrown IAError from findVirtual?
The convention is usually that the VM throws IllegalAccessError and reflective style operations throw Exceptions. We're using the same code to do double duty as the VM is calling into Java for these lookups.
I would expect exception / error conversion to happen at the boundaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has the RI thrown IAError from findVirtual?
Yes. This matches the behaviour of the reference implementation.
/*[MSG "K0587", "'{0}' no access to: '{1}'"]*/ | ||
throw new IllegalAccessException(com.ibm.oti.util.Msg.getString("K0587", accessClass.getName(), targetClass.getName())); //$NON-NLS-1$ | ||
} | ||
|
||
void checkLookupVisibility(Class<?> targetClass) throws IllegalAccessException, IllegalAccessError { | ||
if (this.equals(PUBLIC_LOOKUP)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than checking is identically PUBLIC_LOOKUP, we should check for the UNCONDITIONAL
mode access bit - see https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/MethodHandles.html#publicLookup--
* @param targetClass Class which the referring class is accessing | ||
* @throws IllegalAccessException if the targetClass is not visible | ||
*/ | ||
static void checkClassModuleVisibility(Module accessModule, Class<?> targetClass) throws IllegalAccessError, IllegalAccessException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably also needs to take the UNCONDITIONAL
access bit into account (ie: public lookup)
1ea8a4b
to
032fe21
Compare
The current change causes a regression in another test. I am investigating. |
032fe21
to
19f688c
Compare
Check that the target class, parameter types, and return types of a method handle are obey module access restrictions. Signed-off-by: Peter Bain <peter_bain@ca.ibm.com>
19f688c
to
d137536
Compare
Regression was due to stale base code. |
@DanHeidinga or @pshipton do you have any comments on this PR? If not, could you Thank you. |
Jenkins test sanity plinux jdk8,jdk9 |
Ensure target classes, paramater types, and return types are visible.
Signed-off-by: Peter Bain peter_bain@ca.ibm.com