@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
final String[] exceptions) {
annotate();
final MethodVisitor originalMethod = super.visitMethod(access, name, desc, signature, exceptions);
final Method methd = new Method(name, desc);
return new GeneratorAdapter(Opcodes.ASM4, originalMethod, access, name, desc) {
@Override
public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
if (Type.getType(Privileged.class).getDescriptor().equals(desc)) {
final AccessLevel localAccessLevel = AccessLevel.of(access);
if (accessLevel.compareTo(localAccessLevel) > 0) {
throw new RuntimeException(new IllegalAccessException("Method " + className + "#" + methd
+ " must have maximum access level '" + accessLevel + "' but is defined wider ('"
+ localAccessLevel + "')"));
}
if (AccessLevel.PACKAGE.compareTo(accessLevel) > 0) {
privilizer().env.warn("Possible security leak: granting privileges to %s method %s.%s",
localAccessLevel, className, methd);
}
privilegedMethods.put(methd, privilizer().generateName(name));
}
return super.visitAnnotation(desc, visible);
}
@Override
public void visitCode() {
super.visitCode();
if (!privilegedMethods.containsKey(methd)) {
return;
}
final String impl = privilegedMethods.get(methd);
final boolean instanceMethod = !Modifier.isStatic(access);
if (policy.isConditional()) {
privilizer().env.debug("setting up conditional execution due to policy %s", policy);
// test, loading boolean
if (policy == Policy.ON_INIT) {
getStatic(target, privilizer().generateName("hasSecurityManager"), Type.BOOLEAN_TYPE);
} else if (policy == Policy.DYNAMIC) {
checkSecurityManager(this);
}
final Label doPrivileged = new Label();
// if true, goto doPrivileged:
ifZCmp(NE, doPrivileged);
final Method implMethod = new Method(impl, desc);
if (instanceMethod) {
loadThis();
loadArgs();
invokeVirtual(target, implMethod);
} else {
loadArgs();
invokeStatic(target, implMethod);
}
returnValue();
mark(doPrivileged);
} else {
privilizer().env.debug("setting up unconditional privileged execution due to policy %s", policy);
}
// generate action:
final Type[] ctorArgs;
if (instanceMethod) {
ctorArgs = ArrayUtils.add(methd.getArgumentTypes(), 0, target);
} else {
ctorArgs = methd.getArgumentTypes();
}
final Type actionType = new ActionGenerator(access, methd, exceptions, PrivilizingVisitor.this).build();
newInstance(actionType);
dup();
if (instanceMethod) {
loadThis();
}
loadArgs();
invokeConstructor(actionType, new Method("<init>", Type.VOID_TYPE, ctorArgs));
final boolean exc = ArrayUtils.isNotEmpty(exceptions);
// mark try if needed
final Label privTry = exc ? mark() : null;
// execute action
final Type arg =
exc ? Type.getType(PrivilegedExceptionAction.class) : Type.getType(PrivilegedAction.class);
final Method doPrivileged = new Method("doPrivileged", Type.getType(Object.class), new Type[] { arg });
invokeStatic(Type.getType(AccessController.class), doPrivileged);
unbox(methd.getReturnType());
returnValue();
if (exc) {
final Type caught = Type.getType(PrivilegedActionException.class);
// end try
final Label privCatch = mark();
// catch
catchException(privTry, privCatch, caught);
// unwrap
invokeVirtual(caught, new Method("getException", Type.getType(Exception.class),
Privilizer.EMPTY_TYPE_ARRAY));
// throw
throwException();
}