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,9 +22,10 @@ import com.mumfrey.liteloader.interfaces.ObjectFactory; | ||
22 | */ | 22 | */ |
23 | public class LiteLoaderCoreAPIClient extends LiteLoaderCoreAPI | 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 | private static final String[] requiredTransformers = { | 27 | private static final String[] requiredTransformers = { |
28 | + LiteLoaderCoreAPI.PKG_LITELOADER + ".transformers.event.EventProxyTransformer", | ||
28 | LiteLoaderCoreAPI.PKG_LITELOADER + ".launch.LiteLoaderTransformer", | 29 | LiteLoaderCoreAPI.PKG_LITELOADER + ".launch.LiteLoaderTransformer", |
29 | LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.CrashReportTransformer" | 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,11 +106,7 @@ public class RealmsJsonUpdateThread extends Thread | ||
106 | 106 | ||
107 | private boolean writeLocalVersionJson(Map<String, ?> localJson) | 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 | FileWriter writer = null; | 110 | FileWriter writer = null; |
115 | 111 | ||
116 | try | 112 | try |
@@ -227,11 +223,8 @@ public class RealmsJsonUpdateThread extends Thread | @@ -227,11 +223,8 @@ public class RealmsJsonUpdateThread extends Thread | ||
227 | @SuppressWarnings("unchecked") | 223 | @SuppressWarnings("unchecked") |
228 | private Map<String, ?> getLocalVersionJson() | 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 | FileReader reader = null; | 229 | FileReader reader = null; |
237 | 230 | ||
@@ -254,13 +247,22 @@ public class RealmsJsonUpdateThread extends Thread | @@ -254,13 +247,22 @@ public class RealmsJsonUpdateThread extends Thread | ||
254 | 247 | ||
255 | private boolean isLocalJsonUpToDate() | 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 | long deltaTime = System.currentTimeMillis() - versionJsonFile.lastModified(); | 253 | long deltaTime = System.currentTimeMillis() - versionJsonFile.lastModified(); |
264 | return deltaTime < 86400000; | 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,14 +10,11 @@ import java.util.Set; | ||
10 | import java.util.TreeSet; | 10 | import java.util.TreeSet; |
11 | 11 | ||
12 | import org.objectweb.asm.ClassWriter; | 12 | import org.objectweb.asm.ClassWriter; |
13 | -import org.objectweb.asm.Opcodes; | ||
14 | import org.objectweb.asm.tree.AbstractInsnNode; | 13 | import org.objectweb.asm.tree.AbstractInsnNode; |
15 | import org.objectweb.asm.tree.ClassNode; | 14 | import org.objectweb.asm.tree.ClassNode; |
16 | -import org.objectweb.asm.tree.InsnNode; | ||
17 | import org.objectweb.asm.tree.MethodNode; | 15 | import org.objectweb.asm.tree.MethodNode; |
18 | import org.objectweb.asm.util.CheckClassAdapter; | 16 | import org.objectweb.asm.util.CheckClassAdapter; |
19 | 17 | ||
20 | -import com.mumfrey.liteloader.core.runtime.Obf; | ||
21 | import com.mumfrey.liteloader.transformers.ClassTransformer; | 18 | import com.mumfrey.liteloader.transformers.ClassTransformer; |
22 | import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | 19 | import com.mumfrey.liteloader.util.log.LiteLoaderLogger; |
23 | 20 | ||
@@ -59,7 +56,7 @@ public abstract class EventInjectionTransformer extends ClassTransformer | @@ -59,7 +56,7 @@ public abstract class EventInjectionTransformer extends ClassTransformer | ||
59 | /** | 56 | /** |
60 | * Multiple event injection transformers may exist but to allow co-operation the events themselves are registered | 57 | * Multiple event injection transformers may exist but to allow co-operation the events themselves are registered |
61 | * statically. The first EventInjectionTransformer instance to be created becomes the "master" and is actually responsible | 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 | private static EventInjectionTransformer master; | 61 | private static EventInjectionTransformer master; |
65 | 62 | ||
@@ -156,23 +153,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer | @@ -156,23 +153,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer | ||
156 | { | 153 | { |
157 | if (EventInjectionTransformer.master == this) | 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 | if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName)) | 156 | if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName)) |
177 | { | 157 | { |
178 | return this.injectEvents(basicClass, EventInjectionTransformer.eventMappings.get(transformedName)); | 158 | return this.injectEvents(basicClass, EventInjectionTransformer.eventMappings.get(transformedName)); |
@@ -182,36 +162,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer | @@ -182,36 +162,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer | ||
182 | return basicClass; | 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 | private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings) | 165 | private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings) |
216 | { | 166 | { |
217 | if (mappings == null) return basicClass; | 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 | +} |