SPIGOT-2645: Better PluginClassLoader safety

By: md_5 <git@md-5.net>
This commit is contained in:
Bukkit/Spigot
2016-09-01 09:07:32 +10:00
parent 4be07ca07a
commit a037aff506

View File

@@ -7,12 +7,12 @@ import java.io.InputStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.logging.Level; import java.util.logging.Level;
@@ -49,7 +49,7 @@ public final class JavaPluginLoader implements PluginLoader {
final Server server; final Server server;
private final Pattern[] fileFilters = new Pattern[] { Pattern.compile("\\.jar$"), }; private final Pattern[] fileFilters = new Pattern[] { Pattern.compile("\\.jar$"), };
private final Map<String, Class<?>> classes = new HashMap<String, Class<?>>(); private final Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
private final Map<String, PluginClassLoader> loaders = Collections.synchronizedMap(new LinkedHashMap<String, PluginClassLoader>()); private final List<PluginClassLoader> loaders = new CopyOnWriteArrayList<PluginClassLoader>();
/** /**
* This class was not meant to be constructed explicitly * This class was not meant to be constructed explicitly
@@ -115,7 +115,7 @@ public final class JavaPluginLoader implements PluginLoader {
} }
for (final String pluginName : description.getDepend()) { for (final String pluginName : description.getDepend()) {
PluginClassLoader current = loaders.get(pluginName); Plugin current = server.getPluginManager().getPlugin(pluginName);
if (current == null) { if (current == null) {
throw new UnknownDependencyException(pluginName); throw new UnknownDependencyException(pluginName);
@@ -131,7 +131,7 @@ public final class JavaPluginLoader implements PluginLoader {
throw new InvalidPluginException(ex); throw new InvalidPluginException(ex);
} }
loaders.put(description.getName(), loader); loaders.add(loader);
return loader.plugin; return loader.plugin;
} }
@@ -184,8 +184,7 @@ public final class JavaPluginLoader implements PluginLoader {
if (cachedClass != null) { if (cachedClass != null) {
return cachedClass; return cachedClass;
} else { } else {
synchronized (loaders) { for (PluginClassLoader loader : loaders) {
for (PluginClassLoader loader : loaders.values()) {
try { try {
cachedClass = loader.findClass(name, false); cachedClass = loader.findClass(name, false);
} catch (ClassNotFoundException cnfe) {} } catch (ClassNotFoundException cnfe) {}
@@ -194,7 +193,6 @@ public final class JavaPluginLoader implements PluginLoader {
} }
} }
} }
}
return null; return null;
} }
@@ -320,10 +318,11 @@ public final class JavaPluginLoader implements PluginLoader {
JavaPlugin jPlugin = (JavaPlugin) plugin; JavaPlugin jPlugin = (JavaPlugin) plugin;
String pluginName = jPlugin.getDescription().getName(); PluginClassLoader pluginLoader = (PluginClassLoader) jPlugin.getClassLoader();
if (!loaders.containsKey(pluginName)) { if (!loaders.contains(pluginLoader)) {
loaders.put(pluginName, (PluginClassLoader) jPlugin.getClassLoader()); loaders.add(pluginLoader);
server.getLogger().log(Level.WARNING, "Enabled plugin with unregistered PluginClassLoader " + plugin.getDescription().getFullName());
} }
try { try {
@@ -356,10 +355,10 @@ public final class JavaPluginLoader implements PluginLoader {
server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
} }
loaders.remove(jPlugin.getDescription().getName());
if (cloader instanceof PluginClassLoader) { if (cloader instanceof PluginClassLoader) {
PluginClassLoader loader = (PluginClassLoader) cloader; PluginClassLoader loader = (PluginClassLoader) cloader;
loaders.remove(loader);
Set<String> names = loader.getClasses(); Set<String> names = loader.getClasses();
for (String name : names) { for (String name : names) {