1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.weaver.privilizer;
20
21 import java.lang.reflect.Modifier;
22 import java.security.PrivilegedAction;
23 import java.security.PrivilegedExceptionAction;
24 import java.util.Map;
25
26 import org.apache.commons.lang3.ArrayUtils;
27 import org.apache.commons.lang3.Validate;
28 import org.apache.commons.lang3.builder.Builder;
29 import org.objectweb.asm.ClassWriter;
30 import org.objectweb.asm.Label;
31 import org.objectweb.asm.Opcodes;
32 import org.objectweb.asm.Type;
33 import org.objectweb.asm.commons.GeneratorAdapter;
34 import org.objectweb.asm.commons.Method;
35 import org.objectweb.asm.signature.SignatureReader;
36 import org.objectweb.asm.signature.SignatureVisitor;
37 import org.objectweb.asm.signature.SignatureWriter;
38
39
40
41
42 class ActionGenerator extends Privilizer.WriteClass implements Builder<Type> {
43 final PrivilizingVisitor owner;
44 final Method methd;
45 final boolean exc;
46 final Type[] exceptions;
47 final String simpleName;
48 final Type action;
49 final Method impl;
50 final int index;
51 final boolean implIsStatic;
52 final Method helper;
53 final Type result;
54 final Field[] fields;
55 private final Type actionInterface;
56
57
58
59
60
61
62
63
64 ActionGenerator(final int access, final Method methd, final String[] exceptions, final PrivilizingVisitor owner) {
65 owner.privilizer().super(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
66 this.methd = methd;
67 this.exc = ArrayUtils.isNotEmpty(exceptions);
68 this.exceptions = exc ? new Type[] { Type.getType(Exception.class) } : null;
69 this.owner = owner;
70 this.simpleName = generateName(methd);
71 this.action = Type.getObjectType(owner.className + '$' + simpleName);
72
73 int privilegedAccessIndex = -1;
74 String implName = null;
75 for (final Map.Entry<Method, String> entry : owner.privilegedMethods.entrySet()) {
76 privilegedAccessIndex++;
77 if (entry.getKey().equals(methd)) {
78 implName = entry.getValue();
79 break;
80 }
81 }
82 Validate.validState(implName != null);
83
84 this.index = privilegedAccessIndex;
85
86 this.impl = new Method(implName, methd.getDescriptor());
87 this.implIsStatic = Modifier.isStatic(access);
88 final Type[] args =
89 implIsStatic ? methd.getArgumentTypes() : ArrayUtils.insert(0, methd.getArgumentTypes(), owner.target);
90 this.helper = new Method(privilizer().generateName("access$" + index), methd.getReturnType(), args);
91 this.result = Privilizer.wrap(methd.getReturnType());
92 this.fields = fields(args);
93 this.actionInterface = Type.getType(exc ? PrivilegedExceptionAction.class : PrivilegedAction.class);
94 }
95
96 private static String generateName(final Method methd) {
97 final StringBuilder buf = new StringBuilder(methd.getName());
98 if (methd.getArgumentTypes().length > 0) {
99 buf.append("$$");
100 for (final Type arg : methd.getArgumentTypes()) {
101 buf.append(arg.getDescriptor().replace("[", "arrayOf").replace('/', '_').replace(';', '$'));
102 }
103 }
104 return buf.append("_ACTION").toString();
105 }
106
107 @SuppressWarnings("PMD.UseVarargs")
108 private static Field[] fields(final Type[] args) {
109 final Field[] result = new Field[args.length];
110
111 for (int i = 0; i < args.length; i++) {
112 final String name = new StringBuilder("f").append(i + 1).toString();
113 result[i] = new Field(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, name, args[i]);
114 }
115 return result;
116 }
117
118 @Override
119 public Type build() {
120 generateHelper();
121 begin();
122 init();
123 impl();
124 visitEnd();
125 owner.privilizer().env.debug("Generated %s implementation %s to call %s#%s", actionInterface.getClassName(),
126 action.getClassName(), owner.target.getClassName(), helper);
127 return action;
128 }
129
130
131
132
133
134
135 private void generateHelper() {
136 owner.privilizer().env.debug("Generating static helper method %s.%s to call %s", owner.target.getClassName(),
137 helper, impl);
138 final GeneratorAdapter mgen =
139 new GeneratorAdapter(Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, helper, null, exceptions, owner);
140
141 mgen.visitCode();
142 mgen.loadArgs();
143 if (implIsStatic) {
144 mgen.invokeStatic(owner.target, impl);
145 } else {
146 mgen.invokeVirtual(owner.target, impl);
147 }
148 mgen.returnValue();
149 mgen.endMethod();
150 }
151
152 private void begin() {
153 owner.visitInnerClass(action.getInternalName(), owner.className, simpleName, Opcodes.ACC_PRIVATE
154 | Opcodes.ACC_STATIC);
155
156 final SignatureWriter type = new SignatureWriter();
157 final SignatureVisitor actionImplemented = type.visitInterface();
158 actionImplemented.visitClassType(actionInterface.getInternalName());
159 final SignatureVisitor visitTypeArgument = actionImplemented.visitTypeArgument('=');
160 new SignatureReader(Privilizer.wrap(methd.getReturnType()).getDescriptor()).accept(visitTypeArgument);
161 actionImplemented.visitEnd();
162
163 final String signature = type.toString();
164
165 visit(Opcodes.V1_5, Opcodes.ACC_SUPER | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL, action.getInternalName(),
166 signature, Type.getType(Object.class).getInternalName(),
167 new String[] { actionInterface.getInternalName() });
168 }
169
170
171
172
173 private void init() {
174 for (final Field field : fields) {
175 visitField(field.access, field.name, field.type.getDescriptor(), null, null).visitEnd();
176 }
177 final Method init = new Method("<init>", Type.VOID_TYPE, helper.getArgumentTypes());
178
179 final GeneratorAdapter mgen =
180 new GeneratorAdapter(0, init, null, Privilizer.EMPTY_TYPE_ARRAY, this);
181
182 mgen.visitCode();
183 final Label begin = mgen.mark();
184
185
186 mgen.loadThis();
187 mgen.invokeConstructor(Type.getType(Object.class), Method.getMethod("void <init> ()"));
188
189
190 int arg = 0;
191 for (final Field field : fields) {
192 mgen.loadThis();
193 mgen.loadArg(arg++);
194 mgen.putField(action, field.name, field.type);
195 }
196 mgen.returnValue();
197 final Label end = mgen.mark();
198
199
200 mgen.visitLocalVariable("this", action.getDescriptor(), null, begin, end, 0);
201 arg = 1;
202 for (final Field field : fields) {
203 mgen.visitLocalVariable("arg" + arg, field.type.getDescriptor(), null, begin, end, arg++);
204 }
205 mgen.endMethod();
206 }
207
208
209
210
211 private void impl() {
212 final Method run = Method.getMethod("Object run()");
213
214 final GeneratorAdapter mgen = new GeneratorAdapter(Opcodes.ACC_PUBLIC, run, null, exceptions, this);
215
216 for (final Field field : fields) {
217 mgen.loadThis();
218 mgen.getField(action, field.name, field.type);
219 }
220 mgen.invokeStatic(owner.target, helper);
221
222 if (methd.getReturnType().getSort() < Type.ARRAY) {
223 mgen.valueOf(methd.getReturnType());
224 }
225 mgen.returnValue();
226 mgen.endMethod();
227 }
228 }