Commit 3340467d961b639381483255b3d01009a21aee66
1 parent
00d2ffc1
separating event proxy generation to improve resilience against bad transformers
Showing
4 changed files
with
95 additions
and
67 deletions
java/client/com/mumfrey/liteloader/client/api/LiteLoaderCoreAPIClient.java
... | ... | @@ -22,9 +22,10 @@ import com.mumfrey.liteloader.interfaces.ObjectFactory; |
22 | 22 | */ |
23 | 23 | public class LiteLoaderCoreAPIClient extends LiteLoaderCoreAPI |
24 | 24 | { |
25 | - private static final String PKG_LITELOADER_CLIENT = LiteLoaderCoreAPI.PKG_LITELOADER + ".client"; | |
25 | + private static final String PKG_LITELOADER_CLIENT = LiteLoaderCoreAPI.PKG_LITELOADER + ".client"; | |
26 | 26 | |
27 | 27 | private static final String[] requiredTransformers = { |
28 | + LiteLoaderCoreAPI.PKG_LITELOADER + ".transformers.event.EventProxyTransformer", | |
28 | 29 | LiteLoaderCoreAPI.PKG_LITELOADER + ".launch.LiteLoaderTransformer", |
29 | 30 | LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.CrashReportTransformer" |
30 | 31 | }; | ... | ... |
java/common/com/mumfrey/liteloader/launch/RealmsJsonUpdateThread.java
... | ... | @@ -106,11 +106,7 @@ public class RealmsJsonUpdateThread extends Thread |
106 | 106 | |
107 | 107 | private boolean writeLocalVersionJson(Map<String, ?> localJson) |
108 | 108 | { |
109 | - File versionDir = new File(this.versionsDir, this.version); | |
110 | - if (!versionDir.exists() || !versionDir.isDirectory()) return false; | |
111 | - | |
112 | - File versionJsonFile = new File(versionDir, this.version + ".json"); | |
113 | - | |
109 | + File versionJsonFile = this.getLocalVersionJsonFile(); | |
114 | 110 | FileWriter writer = null; |
115 | 111 | |
116 | 112 | try |
... | ... | @@ -227,11 +223,8 @@ public class RealmsJsonUpdateThread extends Thread |
227 | 223 | @SuppressWarnings("unchecked") |
228 | 224 | private Map<String, ?> getLocalVersionJson() |
229 | 225 | { |
230 | - File versionDir = new File(this.versionsDir, this.version); | |
231 | - if (!versionDir.exists() || !versionDir.isDirectory()) return null; | |
232 | - | |
233 | - File versionJsonFile = new File(versionDir, this.version + ".json"); | |
234 | - if (!versionJsonFile.exists()) return null; | |
226 | + File versionJsonFile = this.getLocalVersionJsonFile(); | |
227 | + if (versionJsonFile == null || !versionJsonFile.exists()) return null; | |
235 | 228 | |
236 | 229 | FileReader reader = null; |
237 | 230 | |
... | ... | @@ -254,13 +247,22 @@ public class RealmsJsonUpdateThread extends Thread |
254 | 247 | |
255 | 248 | private boolean isLocalJsonUpToDate() |
256 | 249 | { |
257 | - File versionDir = new File(this.versionsDir, this.version); | |
258 | - if (!versionDir.exists() || !versionDir.isDirectory()) return false; | |
259 | - | |
260 | - File versionJsonFile = new File(versionDir, this.version + ".json"); | |
261 | - if (!versionJsonFile.exists()) return false; | |
250 | + File versionJsonFile = this.getLocalVersionJsonFile(); | |
251 | + if (versionJsonFile == null || !versionJsonFile.exists()) return false; | |
262 | 252 | |
263 | 253 | long deltaTime = System.currentTimeMillis() - versionJsonFile.lastModified(); |
264 | 254 | return deltaTime < 86400000; |
265 | 255 | } |
256 | + | |
257 | + /** | |
258 | + * @return | |
259 | + */ | |
260 | + private File getLocalVersionJsonFile() | |
261 | + { | |
262 | + File versionDir = new File(this.versionsDir, this.version); | |
263 | + if (!versionDir.exists() || !versionDir.isDirectory()) return null; | |
264 | + | |
265 | + File versionJsonFile = new File(versionDir, this.version + ".json"); | |
266 | + return versionJsonFile; | |
267 | + } | |
266 | 268 | } | ... | ... |
java/common/com/mumfrey/liteloader/transformers/event/EventInjectionTransformer.java
... | ... | @@ -10,14 +10,11 @@ import java.util.Set; |
10 | 10 | import java.util.TreeSet; |
11 | 11 | |
12 | 12 | import org.objectweb.asm.ClassWriter; |
13 | -import org.objectweb.asm.Opcodes; | |
14 | 13 | import org.objectweb.asm.tree.AbstractInsnNode; |
15 | 14 | import org.objectweb.asm.tree.ClassNode; |
16 | -import org.objectweb.asm.tree.InsnNode; | |
17 | 15 | import org.objectweb.asm.tree.MethodNode; |
18 | 16 | import org.objectweb.asm.util.CheckClassAdapter; |
19 | 17 | |
20 | -import com.mumfrey.liteloader.core.runtime.Obf; | |
21 | 18 | import com.mumfrey.liteloader.transformers.ClassTransformer; |
22 | 19 | import com.mumfrey.liteloader.util.log.LiteLoaderLogger; |
23 | 20 | |
... | ... | @@ -59,7 +56,7 @@ public abstract class EventInjectionTransformer extends ClassTransformer |
59 | 56 | /** |
60 | 57 | * Multiple event injection transformers may exist but to allow co-operation the events themselves are registered |
61 | 58 | * statically. The first EventInjectionTransformer instance to be created becomes the "master" and is actually responsible |
62 | - * for injecting the events and transforming the EventProxy class. | |
59 | + * for injecting the events | |
63 | 60 | */ |
64 | 61 | private static EventInjectionTransformer master; |
65 | 62 | |
... | ... | @@ -156,23 +153,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer |
156 | 153 | { |
157 | 154 | if (EventInjectionTransformer.master == this) |
158 | 155 | { |
159 | - if (transformedName != null && transformedName.startsWith(Obf.EventProxy.name)) | |
160 | - { | |
161 | - int dollarPos = transformedName.indexOf('$'); | |
162 | - int proxyIndex = (dollarPos > -1) ? Integer.parseInt(transformedName.substring(dollarPos + 1)) : 0; | |
163 | - if (proxyIndex != 1) | |
164 | - { | |
165 | - try | |
166 | - { | |
167 | - return this.transformEventProxy(transformedName, basicClass, proxyIndex); | |
168 | - } | |
169 | - catch (Throwable th) | |
170 | - { | |
171 | - th.printStackTrace(); | |
172 | - } | |
173 | - } | |
174 | - } | |
175 | - | |
176 | 156 | if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName)) |
177 | 157 | { |
178 | 158 | return this.injectEvents(basicClass, EventInjectionTransformer.eventMappings.get(transformedName)); |
... | ... | @@ -182,36 +162,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer |
182 | 162 | return basicClass; |
183 | 163 | } |
184 | 164 | |
185 | - private byte[] transformEventProxy(String transformedName, byte[] basicClass, int proxyIndex) | |
186 | - { | |
187 | - ClassNode classNode = this.getProxyByteCode(transformedName, basicClass, proxyIndex); | |
188 | - return this.writeClass(Event.populateProxy(classNode, proxyIndex == 0 ? 1 : proxyIndex)); | |
189 | - } | |
190 | - | |
191 | - private ClassNode getProxyByteCode(String transformedName, byte[] basicClass, int proxyIndex) | |
192 | - { | |
193 | - if (proxyIndex == 0 || basicClass != null) | |
194 | - { | |
195 | - ClassNode classNode = this.readClass(basicClass, true); | |
196 | - | |
197 | - for (MethodNode method : classNode.methods) | |
198 | - { | |
199 | - // Strip the sanity code out of the EventProxy class initialiser | |
200 | - if ("<clinit>".equals(method.name)) | |
201 | - { | |
202 | - method.instructions.clear(); | |
203 | - method.instructions.add(new InsnNode(Opcodes.RETURN)); | |
204 | - } | |
205 | - } | |
206 | - | |
207 | - return classNode; | |
208 | - } | |
209 | - | |
210 | - ClassNode classNode = new ClassNode(); | |
211 | - classNode.visit(50, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, transformedName.replace('.', '/'), null, "java/lang/Object", null); | |
212 | - return classNode; | |
213 | - } | |
214 | - | |
215 | 165 | private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings) |
216 | 166 | { |
217 | 167 | if (mappings == null) return basicClass; | ... | ... |
java/common/com/mumfrey/liteloader/transformers/event/EventProxyTransformer.java
0 → 100644
1 | +package com.mumfrey.liteloader.transformers.event; | |
2 | + | |
3 | +import org.objectweb.asm.Opcodes; | |
4 | +import org.objectweb.asm.tree.ClassNode; | |
5 | +import org.objectweb.asm.tree.InsnNode; | |
6 | +import org.objectweb.asm.tree.MethodNode; | |
7 | + | |
8 | +import com.mumfrey.liteloader.core.runtime.Obf; | |
9 | +import com.mumfrey.liteloader.transformers.ClassTransformer; | |
10 | + | |
11 | +/** | |
12 | + * Transformer responsible for transforming/generating the EventProxy inner classes, separated from the Event Transformer | |
13 | + * itself so that we can place it higher up the tranformer chain to avoid broken mod transformers screwing things up. | |
14 | + * | |
15 | + * @author Adam Mummery-Smith | |
16 | + */ | |
17 | +public class EventProxyTransformer extends ClassTransformer | |
18 | +{ | |
19 | + public EventProxyTransformer() | |
20 | + { | |
21 | + } | |
22 | + | |
23 | + @Override | |
24 | + public byte[] transform(String name, String transformedName, byte[] basicClass) | |
25 | + { | |
26 | + if (transformedName != null && transformedName.startsWith(Obf.EventProxy.name)) | |
27 | + { | |
28 | + int dollarPos = transformedName.indexOf('$'); | |
29 | + int proxyIndex = (dollarPos > -1) ? Integer.parseInt(transformedName.substring(dollarPos + 1)) : 0; | |
30 | + if (proxyIndex != 1) | |
31 | + { | |
32 | + try | |
33 | + { | |
34 | + return this.transformEventProxy(transformedName, basicClass, proxyIndex); | |
35 | + } | |
36 | + catch (Throwable th) | |
37 | + { | |
38 | + th.printStackTrace(); | |
39 | + } | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + return basicClass; | |
44 | + } | |
45 | + | |
46 | + private byte[] transformEventProxy(String transformedName, byte[] basicClass, int proxyIndex) | |
47 | + { | |
48 | + ClassNode classNode = this.getProxyByteCode(transformedName, basicClass, proxyIndex); | |
49 | + return this.writeClass(Event.populateProxy(classNode, proxyIndex == 0 ? 1 : proxyIndex)); | |
50 | + } | |
51 | + | |
52 | + private ClassNode getProxyByteCode(String transformedName, byte[] basicClass, int proxyIndex) | |
53 | + { | |
54 | + if (proxyIndex == 0 || basicClass != null) | |
55 | + { | |
56 | + ClassNode classNode = this.readClass(basicClass, true); | |
57 | + | |
58 | + for (MethodNode method : classNode.methods) | |
59 | + { | |
60 | + // Strip the sanity code out of the EventProxy class initialiser | |
61 | + if ("<clinit>".equals(method.name)) | |
62 | + { | |
63 | + method.instructions.clear(); | |
64 | + method.instructions.add(new InsnNode(Opcodes.RETURN)); | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + return classNode; | |
69 | + } | |
70 | + | |
71 | + ClassNode classNode = new ClassNode(); | |
72 | + classNode.visit(50, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, transformedName.replace('.', '/'), null, "java/lang/Object", null); | |
73 | + return classNode; | |
74 | + } | |
75 | +} | ... | ... |