Commit 3340467d961b639381483255b3d01009a21aee66

Authored by Mumfrey
1 parent 00d2ffc1

separating event proxy generation to improve resilience against bad transformers

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 +}