1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

Always use Unsafe for Bungeecord

This commit is contained in:
Tim203
2021-05-31 16:57:03 +02:00
parent f28f2f2c41
commit 7edb66a692
2 changed files with 20 additions and 96 deletions

View File

@@ -51,21 +51,11 @@ public final class BungeeInjector extends CommonPlatformInjector {
Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender"); Field framePrepender = ReflectionUtils.getField(PipelineUtils.class, "framePrepender");
if (!BungeeReflectionUtils.isJava16()) {
// we have to remove the final modifier before asking for the value
// because we can't remove it after we got the current value
BungeeReflectionUtils.removeFinal(framePrepender);
}
BungeeCustomPrepender customPrepender = new BungeeCustomPrepender( BungeeCustomPrepender customPrepender = new BungeeCustomPrepender(
ReflectionUtils.getCastedValue(null, framePrepender), logger ReflectionUtils.getCastedValue(null, framePrepender), logger
); );
if (BungeeReflectionUtils.isJava16()) { BungeeReflectionUtils.setFieldValue(null, framePrepender, customPrepender);
BungeeReflectionUtils.setJava16Field(null, framePrepender, customPrepender);
} else {
ReflectionUtils.setValue(null, framePrepender, customPrepender);
}
injected = true; injected = true;
return true; return true;

View File

@@ -26,81 +26,37 @@
package org.geysermc.floodgate.util; package org.geysermc.floodgate.util;
import static org.geysermc.floodgate.util.MessageFormatter.format; import static org.geysermc.floodgate.util.MessageFormatter.format;
import static org.geysermc.floodgate.util.ReflectionUtils.castedInvoke;
import static org.geysermc.floodgate.util.ReflectionUtils.getMethod;
import static org.geysermc.floodgate.util.ReflectionUtils.makeAccessible;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import sun.misc.Unsafe;
// Reflection for just Bungee specific reflection because Bungee doesn't like accessibility :) // Reflection just for Bungee because Bungee is special :)
public class BungeeReflectionUtils { public class BungeeReflectionUtils {
private static final Field MODIFIERS_FIELD; private static final sun.misc.Unsafe UNSAFE;
private static final Unsafe UNSAFE;
static { static {
Field modifiersField = null; // Should not be null pre-Java-16
Unsafe unsafe = null; // Should not be null post-Java-16
try { try {
modifiersField = Field.class.getDeclaredField("modifiers"); Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
} catch (NoSuchFieldException ignored) { unsafeField.setAccessible(true);
try { UNSAFE = (sun.misc.Unsafe) unsafeField.get(null);
modifiersField = fixJava12Support(); } catch (Exception exception) {
} catch (Exception e) { throw new RuntimeException(format(
if (Constants.DEBUG_MODE) { "Cannot initialize required reflection setup :/\nJava version: {}\nVendor: {} ({})",
e.printStackTrace(); System.getProperty("java.version"),
} System.getProperty("java.vendor"),
System.getProperty("java.vendor.url")
// At this point, we're probably using Java 16 ), exception);
try {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = (Unsafe) unsafeField.get(null);
} catch (Exception exception) {
throw new RuntimeException(format(
"Cannot initialize required reflection setup :/\nJava version: {}\nVendor: {} ({})",
System.getProperty("java.version"),
System.getProperty("java.vendor"),
System.getProperty("java.vendor.url")
), exception);
}
}
} }
MODIFIERS_FIELD = modifiersField;
UNSAFE = unsafe;
} }
private static Field fixJava12Support() throws Exception { public static void setFieldValue(Object object, Field field, Object result) {
// Java 12 compatibility, thanks to https://github.com/powermock/powermock/pull/1010
Method declaredFields = getMethod(Class.class, "getDeclaredFields0", boolean.class);
if (declaredFields == null) {
throw new NoSuchMethodException("Cannot find method getDeclaredFields0");
}
Field[] fields = castedInvoke(Field.class, declaredFields, false);
if (fields == null) {
throw new RuntimeException("The Field class cannot have null fields");
}
for (Field field : fields) {
if ("modifiers".equals(field.getName())) {
return field;
}
}
return null;
}
public static boolean isJava16() {
return UNSAFE != null;
}
public static void setJava16Field(Object object, Field field, Object result) {
try { try {
boolean isStatic = Modifier.isStatic(field.getModifiers()); boolean isStatic = Modifier.isStatic(field.getModifiers());
long offset = isStatic ? UNSAFE.staticFieldOffset(field) : UNSAFE.objectFieldOffset(field);
long offset = isStatic ?
UNSAFE.staticFieldOffset(field) :
UNSAFE.objectFieldOffset(field);
if (isStatic) { if (isStatic) {
UNSAFE.putObject(UNSAFE.staticFieldBase(field), offset, result); UNSAFE.putObject(UNSAFE.staticFieldBase(field), offset, result);
} else { } else {
@@ -108,32 +64,10 @@ public class BungeeReflectionUtils {
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(format( throw new RuntimeException(format(
"Cannot initialize required reflection setup :/\nJava version: {}\nVendor: {} ({})", "Java version: {}\nVendor: {} ({})",
System.getProperty("java.version"), System.getProperty("java.version"),
System.getProperty("java.vendor"), System.getProperty("java.vendor"),
System.getProperty("java.vendor.url"), e)); System.getProperty("java.vendor.url"), e));
} }
} }
/**
* Remove the final modifier of a specific field
*
* @param field the field to remove the final modifier of
* @return true if succeeded
*/
public static boolean removeFinal(Field field) {
try {
makeAccessible(field);
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers)) {
makeAccessible(MODIFIERS_FIELD);
MODIFIERS_FIELD.setInt(field, modifiers & ~Modifier.FINAL);
}
return true;
} catch (Exception exception) {
exception.printStackTrace();
return false;
}
}
} }