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:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user