diff --git a/src/main/java/cpw/mods/fml/common/Loader.java b/src/main/java/cpw/mods/fml/common/Loader.java index 646e1b3..8a2bd19 100644 --- a/src/main/java/cpw/mods/fml/common/Loader.java +++ b/src/main/java/cpw/mods/fml/common/Loader.java @@ -504,12 +504,12 @@ public void preinitializeMods() { - ObjectHolderRegistry.INSTANCE.findObjectHolders(discoverer.getASMTable()); if (!modController.isInState(LoaderState.PREINITIALIZATION)) { FMLLog.warning("There were errors previously. Not beginning mod initialization phase"); return; } + ObjectHolderRegistry.INSTANCE.findObjectHolders(discoverer.getASMTable()); modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir); ObjectHolderRegistry.INSTANCE.applyObjectHolders(); modController.transition(LoaderState.INITIALIZATION, false); diff --git a/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java b/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java index a19ff26..abcbff9 100644 --- a/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java +++ b/src/main/java/cpw/mods/fml/common/asm/transformers/AccessTransformer.java @@ -106,41 +106,10 @@ readMapFile(rulesFile); } - AccessTransformer(JarFile jar) throws IOException - { - Manifest manifest = jar.getManifest(); - String atList = manifest.getMainAttributes().getValue("FMLAT"); - if (atList == null) return; - for (String at : atList.split(" ")) - { - JarEntry jarEntry = jar.getJarEntry("META-INF/"+at); - if (jarEntry != null) - { - processATFile(new JarByteSource(jar,jarEntry).asCharSource(Charsets.UTF_8)); - } - } - FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer mod jar file %s\n", modifiers.size(), jar.getName()); - } - AccessTransformer(Class dummyClazz) { // This is a noop } - private class JarByteSource extends ByteSource { - private JarFile jar; - private JarEntry entry; - public JarByteSource(JarFile jar, JarEntry entry) - { - this.jar = jar; - this.entry = entry; - } - @Override - public InputStream openStream() throws IOException - { - return jar.getInputStream(entry); - } - - } void readMapFile(String rulesFile) throws IOException { File file = new File(rulesFile); @@ -156,7 +125,7 @@ processATFile(Resources.asCharSource(rulesResource, Charsets.UTF_8)); FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer config file %s\n", modifiers.size(), rulesFile); } - private void processATFile(CharSource rulesResource) throws IOException + protected void processATFile(CharSource rulesResource) throws IOException { rulesResource.readLines(new LineProcessor() { diff --git a/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java b/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java index eb442d7..c1a66dd 100644 --- a/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java +++ b/src/main/java/cpw/mods/fml/common/asm/transformers/ModAccessTransformer.java @@ -1,34 +1,71 @@ package cpw.mods.fml.common.asm.transformers; import java.io.IOException; -import java.util.List; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.jar.JarEntry; import java.util.jar.JarFile; -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; +import java.util.jar.Manifest; +import com.google.common.base.Charsets; +import com.google.common.collect.Maps; +import com.google.common.io.ByteSource; +import com.google.common.io.CharSource; +import cpw.mods.fml.relauncher.FMLRelaunchLog; public class ModAccessTransformer extends AccessTransformer { - private static List embedded = Lists.newArrayList(); - public ModAccessTransformer() throws IOException + private static Map embedded = Maps.newHashMap(); //Needs to be primitive so that both classloaders get the same class. + public ModAccessTransformer() throws Exception { super(ModAccessTransformer.class); - for (AccessTransformer at : embedded) - { - mergeModifiers(at.getModifiers()); - } - } + //We are in the new ClassLoader here, so we need to get the static field from the other ClassLoader. + ClassLoader classLoader = this.getClass().getClassLoader().getClass().getClassLoader(); //Bit odd but it gets the class loader that loaded our current class loader yay java! + Class otherClazz = Class.forName(this.getClass().getName(), true, classLoader); + Field otherField = otherClazz.getDeclaredField("embedded"); + otherField.setAccessible(true); + embedded = (Map)otherField.get(null); - private void mergeModifiers(Multimap modifiers) - { - getModifiers().putAll(modifiers); + for (Map.Entry e : embedded.entrySet()) + { + int old_count = getModifiers().size(); + processATFile(CharSource.wrap(e.getValue())); + int added = getModifiers().size() - old_count; + if (added > 0) + { + FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer mod jar file %s\n", added, e.getKey()); + } + } } public static void addJar(JarFile jar) throws IOException { - AccessTransformer at = new AccessTransformer(jar); - if (!at.isEmpty()) + Manifest manifest = jar.getManifest(); + String atList = manifest.getMainAttributes().getValue("FMLAT"); + if (atList == null) return; + for (String at : atList.split(" ")) { - embedded.add(at); + JarEntry jarEntry = jar.getJarEntry("META-INF/"+at); + if (jarEntry != null) + { + embedded.put(String.format("%s!META-INF/%s", jar.getName(), at), + new JarByteSource(jar,jarEntry).asCharSource(Charsets.UTF_8).read()); + } } } + private static class JarByteSource extends ByteSource + { + private JarFile jar; + private JarEntry entry; + public JarByteSource(JarFile jar, JarEntry entry) + { + this.jar = jar; + this.entry = entry; + } + @Override + public InputStream openStream() throws IOException + { + return jar.getInputStream(entry); + } + } } \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/asm/transformers/TerminalTransformer.java b/src/main/java/cpw/mods/fml/common/asm/transformers/TerminalTransformer.java new file mode 100644 index 0000000..cb406de --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/asm/transformers/TerminalTransformer.java @@ -0,0 +1,113 @@ +package cpw.mods.fml.common.asm.transformers; + +import org.objectweb.asm.*; + +import cpw.mods.fml.relauncher.FMLRelaunchLog; +import cpw.mods.fml.relauncher.FMLSecurityManager.ExitTrappedException; +import net.minecraft.launchwrapper.IClassTransformer; + +public class TerminalTransformer implements IClassTransformer +{ + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) + { + ClassReader reader = new ClassReader(basicClass); + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); + + ClassVisitor visitor = writer; + visitor = new ExitVisitor(visitor); + + reader.accept(visitor, 0); + return writer.toByteArray(); + } + + public static class ExitVisitor extends ClassVisitor + { + private String clsName = null; + private static final String callbackOwner = org.objectweb.asm.Type.getInternalName(ExitVisitor.class); + + private ExitVisitor(ClassVisitor cv) + { + super(Opcodes.ASM4, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) + { + super.visit(version, access, name, signature, superName, interfaces); + this.clsName = name; + } + + @Override + public MethodVisitor visitMethod(int mAccess, final String mName, final String mDesc, String mSignature, String[] mExceptions) + { + final boolean warn = !clsName.equals("net/minecraft/client/Minecraft") && + !clsName.equals("net/minecraft/server/dedicated/DedicatedServer") && + !clsName.equals("cpw/mods/fml/common/FMLCommonHandler"); + + return new MethodVisitor(Opcodes.ASM4, super.visitMethod(mAccess, mName, mDesc, mSignature, mExceptions)) + { + public void visitMethodInsn(int opcode, String owner, String name, String desc) + { + if (opcode == Opcodes.INVOKESTATIC && owner.equals("java/lang/System") && name.equals("exit") && desc.equals("(I)V")) + { + if (warn) + { + FMLRelaunchLog.warning("============================================================="); + FMLRelaunchLog.warning("MOD HAS DIRECT REFERENCE System.exit() THIS IS NOT ALLOWED REROUTING TO FMLCommonHandler!"); + FMLRelaunchLog.warning("Offendor: %s.%s%s", ExitVisitor.this.clsName, mName, mDesc); + FMLRelaunchLog.warning("============================================================="); + } + owner = ExitVisitor.callbackOwner; + name = "systemExitCalled"; + } + else if (opcode == Opcodes.INVOKEVIRTUAL && owner.equals("java/lang/Runtime") && name.equals("exit") && desc.equals("(I)V")) + { + if (warn) + { + FMLRelaunchLog.warning("============================================================="); + FMLRelaunchLog.warning("MOD HAS DIRECT REFERENCE Runtime.exit() THIS IS NOT ALLOWED REROUTING TO FMLCommonHandler!"); + FMLRelaunchLog.warning("Offendor: %s.%s%s", ExitVisitor.this.clsName, mName, mDesc); + FMLRelaunchLog.warning("============================================================="); + } + opcode = Opcodes.INVOKESTATIC; + owner = ExitVisitor.callbackOwner; + name = "runtimeExitCalled"; + desc = "(Ljava/lang/Runtime;I)V"; + } + + super.visitMethodInsn(opcode, owner, name, desc); + } + }; + } + + // Intercept System.exit, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException + public static void systemExitCalled(int status) + { + ExitVisitor.checkAccess(); + System.exit(status); + } + // Intercept Runtime.getRuntime().exit, and check if the caller is allowed to use it, if not wrap it in a ExitTrappedException + public static void runtimeExitCalled(Runtime runtime, int status) + { + ExitVisitor.checkAccess(); + runtime.exit(status); + } + + private static void checkAccess() + { + StackTraceElement[] cause = Thread.currentThread().getStackTrace(); + + String callingClass = cause.length > 2 ? cause[3].getClassName() : "none"; + String callingParent = cause.length > 3 ? cause[4].getClassName() : "none"; + // FML is allowed to call system exit and the Minecraft applet (from the quit button), and the dedicated server (from itself) + if (!(callingClass.startsWith("cpw.mods.fml.") || + ("net.minecraft.client.Minecraft".equals(callingClass) && "net.minecraft.client.Minecraft".equals(callingParent)) || + ("net.minecraft.server.dedicated.DedicatedServer".equals(callingClass) && "net.minecraft.server.MinecraftServer".equals(callingParent))) + ) + { + throw new ExitTrappedException(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java b/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java index 4ad84e2..d42067a 100644 --- a/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java +++ b/src/main/java/cpw/mods/fml/common/launcher/FMLInjectionAndSortingTweaker.java @@ -6,6 +6,7 @@ import cpw.mods.fml.relauncher.CoreModManager; import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; /** @@ -30,6 +31,9 @@ { // We sort the tweak list here so that it obeys the tweakordering CoreModManager.sortTweakList(); + @SuppressWarnings("unchecked") + List newTweaks = (List) Launch.blackboard.get("TweakClasses"); + newTweaks.add("cpw.mods.fml.common.launcher.TerminalTweaker"); } run = true; } diff --git a/src/main/java/cpw/mods/fml/common/launcher/TerminalTweaker.java b/src/main/java/cpw/mods/fml/common/launcher/TerminalTweaker.java new file mode 100644 index 0000000..3fd43d0 --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/launcher/TerminalTweaker.java @@ -0,0 +1,32 @@ +package cpw.mods.fml.common.launcher; + +import java.io.File; +import java.util.List; +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.LaunchClassLoader; + +public final class TerminalTweaker implements ITweaker { + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) + { + classLoader.registerTransformer("cpw.mods.fml.common.asm.transformers.TerminalTransformer"); + } + + @Override + public String getLaunchTarget() + { + return null; + } + + @Override + public String[] getLaunchArguments() + { + return new String[0]; + } + + @Override + public void acceptOptions(List args, File gameDir, File assetsDir, String profile) + { + + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraft/client/resources/LanguageManager.java b/src/main/java/net/minecraft/client/resources/LanguageManager.java index 750528b..74b7d12 100644 --- a/src/main/java/net/minecraft/client/resources/LanguageManager.java +++ b/src/main/java/net/minecraft/client/resources/LanguageManager.java @@ -84,8 +84,8 @@ arraylist.add(this.currentLanguage); } - currentLocale.loadLocaleDataFiles(p_110549_1_, arraylist); LanguageRegistry.instance().loadLanguageTable(currentLocale.field_135032_a, this.currentLanguage); + currentLocale.loadLocaleDataFiles(p_110549_1_, arraylist); StringTranslate.replaceWith(currentLocale.field_135032_a); } diff --git a/src/main/resources/fmlversion.properties b/src/main/resources/fmlversion.properties index ab8f578..8ee7168 100644 --- a/src/main/resources/fmlversion.properties +++ b/src/main/resources/fmlversion.properties @@ -1,6 +1,6 @@ fmlbuild.major.number=7 fmlbuild.minor.number=10 -fmlbuild.revision.number=18 -fmlbuild.build.number=60 +fmlbuild.revision.number=23 +fmlbuild.build.number=61 fmlbuild.mcversion=1.7.10 fmlbuild.mcpversion=9.05