From 5b22a60984269e171bdd7d21a8f32ad978c7b5de Mon Sep 17 00:00:00 2001 From: Raven Szewczyk Date: Sun, 30 Jun 2024 10:02:32 +0100 Subject: [PATCH] Fix infinite loop in forge if patch parsing fails, fix compat with upgraded apache-compress --- .../lwjgl3ify/redirects/JarInputStream.java | 18 ++++++++ .../lwjgl3ify/redirects/Pack200.java | 3 ++ .../transformers/ForgePatchTransformer.java | 44 ++++++++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/main/java/me/eigenraven/lwjgl3ify/redirects/JarInputStream.java diff --git a/src/main/java/me/eigenraven/lwjgl3ify/redirects/JarInputStream.java b/src/main/java/me/eigenraven/lwjgl3ify/redirects/JarInputStream.java new file mode 100644 index 00000000..41941de2 --- /dev/null +++ b/src/main/java/me/eigenraven/lwjgl3ify/redirects/JarInputStream.java @@ -0,0 +1,18 @@ +package me.eigenraven.lwjgl3ify.redirects; + +import java.io.EOFException; +import java.io.IOException; +import java.util.jar.JarEntry; + +public final class JarInputStream { + + public static JarEntry getNextJarEntrySafe(final java.util.jar.JarInputStream jis) throws IOException { + try { + return jis.getNextJarEntry(); + } catch (EOFException eof) { + System.err.println("EOF caught while searching for forge patches: " + eof); + eof.printStackTrace(System.err); + return null; + } + } +} diff --git a/src/main/java/me/eigenraven/lwjgl3ify/redirects/Pack200.java b/src/main/java/me/eigenraven/lwjgl3ify/redirects/Pack200.java index 8c4ddfd4..fec89017 100644 --- a/src/main/java/me/eigenraven/lwjgl3ify/redirects/Pack200.java +++ b/src/main/java/me/eigenraven/lwjgl3ify/redirects/Pack200.java @@ -59,11 +59,14 @@ public void unpack(InputStream in, JarOutputStream out) throws IOException { // The Apache library doesn't handle LzmaInputStreams well final byte[] allData = IOUtils.toByteArray(in); parent.unpack(new ByteArrayInputStream(allData), out); + out.flush(); + out.close(); // Forge expects this } @Override public void unpack(File in, JarOutputStream out) throws IOException { parent.unpack(in, out); + out.flush(); } @Override diff --git a/src/main/java/me/eigenraven/lwjgl3ify/rfb/transformers/ForgePatchTransformer.java b/src/main/java/me/eigenraven/lwjgl3ify/rfb/transformers/ForgePatchTransformer.java index d97793af..ceee779b 100644 --- a/src/main/java/me/eigenraven/lwjgl3ify/rfb/transformers/ForgePatchTransformer.java +++ b/src/main/java/me/eigenraven/lwjgl3ify/rfb/transformers/ForgePatchTransformer.java @@ -18,6 +18,7 @@ import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import com.gtnewhorizons.retrofuturabootstrap.api.ClassNodeHandle; @@ -33,12 +34,13 @@ public class ForgePatchTransformer implements RfbClassTransformer { return "forge-patch"; } + public static final String CLASS_PATCH_MANAGER = "cpw.mods.fml.common.patcher.ClassPatchManager"; public static final String TRACING_PRINT_STREAM = "cpw.mods.fml.common.TracingPrintStream"; public static final String FML_SECURITY_MANAGER = "cpw.mods.fml.relauncher.FMLSecurityManager"; public static final String ENUM_HELPER = "net.minecraftforge.common.util.EnumHelper"; - public static final String[] PATCHED_CLASSES = new String[] { TRACING_PRINT_STREAM, FML_SECURITY_MANAGER, - ENUM_HELPER }; + public static final String[] PATCHED_CLASSES = new String[] { CLASS_PATCH_MANAGER, TRACING_PRINT_STREAM, + FML_SECURITY_MANAGER, ENUM_HELPER }; @Override public boolean shouldTransformClass(@NotNull ExtensibleClassLoader classLoader, @@ -59,12 +61,50 @@ public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull return; } switch (className) { + case CLASS_PATCH_MANAGER -> tfClassPatchManager(classNode); case TRACING_PRINT_STREAM -> tfTracingPrintStream(classNode); case FML_SECURITY_MANAGER -> tfFmlSecurityManager(classNode); case ENUM_HELPER -> tfEnumHelper(classNode); } } + private void tfClassPatchManager(@NotNull ClassNodeHandle handle) { + // Fix an infinite loop if an EOFException happens + final ClassNode node = handle.getNode(); + if (node == null || node.methods == null) { + logger.error("Class patch manager missing class data"); + return; + } + for (final MethodNode mn : node.methods) { + if (!"setup".equals(mn.name)) { + continue; + } + if (mn.instructions == null || mn.instructions.size() == 0) { + logger.error("ClassPatchManager#setup(Side) missing code"); + return; + } + for (final AbstractInsnNode insn : mn.instructions) { + if (insn.getOpcode() != INVOKEVIRTUAL) { + continue; + } + if (!(insn instanceof MethodInsnNode minsn)) { + continue; + } + if (!"java/util/jar/JarInputStream".equals(minsn.owner)) { + continue; + } + if (!"getNextJarEntry".equals(minsn.name)) { + continue; + } + // redirect + minsn.setOpcode(INVOKESTATIC); + minsn.owner = "me/eigenraven/lwjgl3ify/redirects/JarInputStream"; + minsn.name = "getNextJarEntrySafe"; + minsn.desc = "(Ljava/util/jar/JarInputStream;)Ljava/util/jar/JarEntry;"; + } + } + } + private void tfTracingPrintStream(@NotNull ClassNodeHandle handle) { // Add a close() override that does not close the underlying stream // Pack200 tries to close this stream when loading patches.