diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerParameterDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerParameterDialog.java index 6aec34def2..3cf3d7da32 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerParameterDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/AbstractDebuggerParameterDialog.java @@ -52,7 +52,6 @@ import ghidra.util.layout.PairLayout; public abstract class AbstractDebuggerParameterDialog
extends DialogComponentProvider implements PropertyChangeListener { - static final String KEY_MEMORIZED_ARGUMENTS = "memorizedArguments"; public static class BigIntEditor extends PropertyEditorSupport { String asText = ""; @@ -435,21 +434,7 @@ public abstract class AbstractDebuggerParameterDialog
extends DialogComponent } } - protected record NameTypePair(String name, Class> type) { - public static NameTypePair fromString(String name) throws ClassNotFoundException { - String[] parts = name.split(",", 2); - if (parts.length != 2) { - // This appears to be a bad assumption - empty fields results in solitary labels - return new NameTypePair(parts[0], String.class); - //throw new IllegalArgumentException("Could not parse name,type"); - } - return new NameTypePair(parts[0], Class.forName(parts[1])); - } - - public final String encodeString() { - return name + "," + type.getName(); - } - } + protected record NameTypePair(String name, Class> type) {} private final BidiMap
paramEditors = new DualLinkedHashBidiMap<>(); @@ -722,46 +707,6 @@ public abstract class AbstractDebuggerParameterDialog
extends DialogComponent
new ValStr<>(editor.getValue(), editor.getAsText()));
}
- public void writeConfigState(SaveState saveState) {
- SaveState subState = new SaveState();
- for (Map.Entry > {
- public static > InvocationDialogHelper waitFor(
- Class > InvocationDialogHelper
+ waitFor(Class dialog.invoke(null));
}
-
- public SaveState saveState() {
- SaveState parent = new SaveState();
- runSwing(() -> dialog.writeConfigState(parent));
- return parent.getSaveState(AbstractDebuggerParameterDialog.KEY_MEMORIZED_ARGUMENTS);
- }
-
- public void loadState(SaveState state) {
- SaveState parent = new SaveState();
- parent.putSaveState(AbstractDebuggerParameterDialog.KEY_MEMORIZED_ARGUMENTS, state);
- runSwing(() -> dialog.readConfigState(parent));
- }
}
diff --git a/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonScriptProvider.java b/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonScriptProvider.java
index 71b408e7e5..7495d7fcdc 100644
--- a/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonScriptProvider.java
+++ b/Ghidra/Extensions/Jython/src/main/java/ghidra/jython/JythonScriptProvider.java
@@ -40,8 +40,7 @@ public class JythonScriptProvider extends AbstractPythonScriptProvider {
throws GhidraScriptLoadException {
try {
- Class> clazz = Class.forName(JythonScript.class.getName());
- GhidraScript script = (GhidraScript) clazz.getConstructor().newInstance();
+ GhidraScript script = new JythonScript();
script.setSourceFile(sourceFile);
return script;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/LocationMemento.java b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/LocationMemento.java
index 7b0c9210e7..b61599477f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/nav/LocationMemento.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/nav/LocationMemento.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,15 +15,16 @@
*/
package ghidra.app.nav;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
import ghidra.framework.options.SaveState;
import ghidra.program.model.listing.Program;
import ghidra.program.util.AddressFieldLocation;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
+import ghidra.util.classfinder.ClassSearcher;
public class LocationMemento {
private static final String PROGRAM_PATH = "PROGRAM_PATH_";
@@ -151,8 +152,8 @@ public class LocationMemento {
}
try {
- Class extends LocationMemento> mementoClass =
- (Class extends LocationMemento>) Class.forName(className);
+ Class extends LocationMemento> mementoClass = ClassSearcher.forNameSafe(className,
+ LocationMemento.class, LocationMemento.class.getClassLoader());
Constructor extends LocationMemento> constructor =
mementoClass.getConstructor(SaveState.class, Program[].class);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
index dd5a9aff76..9fa1cf111d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/headless/HeadlessAnalyzer.java
@@ -54,6 +54,7 @@ import ghidra.program.model.listing.Program;
import ghidra.program.util.GhidraProgramUtilities;
import ghidra.program.util.ProgramLocation;
import ghidra.util.*;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import utilities.util.FileUtilities;
@@ -774,21 +775,21 @@ public class HeadlessAnalyzer {
classLoaderForDotClassScripts =
URLClassLoader.newInstance(urls.toArray(new URL[0]));
- Class> c = Class.forName(className, true, classLoaderForDotClassScripts);
+ ClassSearcher.forNameSafe(className, GhidraScript.class,
+ classLoaderForDotClassScripts);
- if (GhidraScript.class.isAssignableFrom(c)) {
- // No issues, but return null, which signifies we don't actually have a
- // ResourceFile to associate with the script name
- return null;
- }
-
- Msg.error(this,
- "REPORT SCRIPT ERROR: java class '" + className + "' is not a GhidraScript");
+ // No issues, but return null, which signifies we don't actually have a
+ // ResourceFile to associate with the script name
+ return null;
}
catch (ClassNotFoundException e) {
Msg.error(this,
"REPORT SCRIPT ERROR: java class not found for '" + className + "'");
}
+ catch (ClassCastException e) {
+ Msg.error(this,
+ "REPORT SCRIPT ERROR: java class '" + className + "' is not a GhidraScript");
+ }
throw new IllegalArgumentException("Invalid script: " + scriptName);
}
@@ -901,13 +902,14 @@ public class HeadlessAnalyzer {
}
String className = scriptName.substring(0, scriptName.length() - 6);
- Class> c = Class.forName(className, true, classLoaderForDotClassScripts);
+ Class extends GhidraScript> c = ClassSearcher.forNameSafe(className,
+ GhidraScript.class, classLoaderForDotClassScripts);
// Get parent folder to pass to GhidraScript
File parentFile = new File(c.getResource(c.getSimpleName() + ".class").toURI())
.getParentFile();
- currScript = (GhidraScript) c.getConstructor().newInstance();
+ currScript = c.getConstructor().newInstance();
currScript.setScriptArgs(scriptArgs);
if (options.propertiesFilePaths.size() > 0) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/codecompare/panel/CodeComparisonViewState.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/codecompare/panel/CodeComparisonViewState.java
index 9c64c5b3f6..09486c2b83 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/codecompare/panel/CodeComparisonViewState.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/codecompare/panel/CodeComparisonViewState.java
@@ -20,6 +20,7 @@ import java.util.Map.Entry;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginTool;
+import ghidra.util.classfinder.ClassSearcher;
/**
* A state object to save settings each type of comparison view known by the system. This class
@@ -73,9 +74,8 @@ public class CodeComparisonViewState {
String[] names = classStates.getNames();
for (String className : names) {
try {
- @SuppressWarnings("unchecked")
- Class extends CodeComparisonView> clazz =
- (Class extends CodeComparisonView>) Class.forName(className);
+ Class extends CodeComparisonView> clazz = ClassSearcher.forNameSafe(className,
+ CodeComparisonView.class, getClass().getClassLoader());
SaveState classState = classStates.getSaveState(className);
states.put(clazz, classState);
}
diff --git a/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java b/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java
index 9bb943ba02..8d5690a49b 100644
--- a/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java
+++ b/Ghidra/Features/Base/src/main/java/help/screenshot/AbstractScreenShotGenerator.java
@@ -15,7 +15,8 @@
*/
package help.screenshot;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.awt.*;
import java.awt.geom.GeneralPath;
@@ -80,6 +81,7 @@ import ghidra.program.util.ProgramSelection;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.ColorUtils;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.UsrException;
import ghidra.util.task.TaskMonitor;
@@ -1355,10 +1357,9 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
public Plugin loadPlugin(String className) {
try {
- Class> clazz = Class.forName(className);
- @SuppressWarnings("unchecked")
- Class extends Plugin> pluginClazz = (Class extends Plugin>) clazz;
- return loadPlugin(pluginClazz);
+ Class extends Plugin> clazz =
+ ClassSearcher.forNameSafe(className, Plugin.class, getClass().getClassLoader());
+ return loadPlugin(clazz);
}
catch (ClassCastException e) {
e.printStackTrace();
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java
index bb7cba6f52..ab2ad9cd29 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/plugintool/dialog/ManagePlugins2Test.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,8 +15,8 @@
*/
package ghidra.framework.plugintool.dialog;
-import static org.hamcrest.collection.IsEmptyCollection.*;
-import static org.hamcrest.core.IsNot.*;
+import static org.hamcrest.collection.IsEmptyCollection.empty;
+import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.*;
import java.util.*;
@@ -31,6 +31,7 @@ import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
+import ghidra.util.classfinder.ClassSearcher;
import resources.Icons;
/**
@@ -372,9 +373,9 @@ public class ManagePlugins2Test extends AbstractGhidraHeadedIntegrationTest {
private void loadPlugin(String name) {
try {
- Class> clazz = Class.forName(name);
- Plugin plugin =
- (Plugin) clazz.getDeclaredConstructor(PluginTool.class).newInstance(tool);
+ Class extends Plugin> clazz =
+ ClassSearcher.forNameSafe(name, Plugin.class, getClass().getClassLoader());
+ Plugin plugin = clazz.getDeclaredConstructor(PluginTool.class).newInstance(tool);
loadedPlugins.add(plugin);
}
catch (Exception e) {
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/test/TestKeyEventDispatcher.java b/Ghidra/Framework/Docking/src/main/java/docking/test/TestKeyEventDispatcher.java
index 4c3d4996a1..baeb0fbdf4 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/test/TestKeyEventDispatcher.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/test/TestKeyEventDispatcher.java
@@ -22,7 +22,6 @@ import javax.swing.SwingUtilities;
import docking.FocusOwnerProvider;
import generic.test.TestUtils;
-import ghidra.util.Msg;
/**
* A class that helps to delegate key events to the system override key event dispatcher. This
@@ -64,30 +63,22 @@ public class TestKeyEventDispatcher {
}
private static KeyEventDispatcher getOverriddenKeyEventDispatcher() {
-
// Note: our custom key event dispatcher has package access, so we cannot refer to
// it directly
- try {
- Class> clazz = Class.forName("docking.KeyBindingOverrideKeyEventDispatcher");
- Object customDispatcher = TestUtils.getInstanceField("instance", clazz);
- if (customDispatcher == null) {
- return null; // not installed
- }
-
- //
- // Dependency Inject our own focus provider so that we can force the event
- // dispatcher to deliver events to our component
- //
- TestUtils.invokeInstanceMethod("setFocusOwnerProvider", customDispatcher,
- FocusOwnerProvider.class, focusProvider);
-
- return (KeyEventDispatcher) customDispatcher;
- }
- catch (ClassNotFoundException e) {
- Msg.error(TestKeyEventDispatcher.class, "Unable to find the system KeyEventDispatcher",
- e);
- return null;
+ Class> clazz = docking.KeyBindingOverrideKeyEventDispatcher.class;
+ Object customDispatcher = TestUtils.getInstanceField("instance", clazz);
+ if (customDispatcher == null) {
+ return null; // not installed
}
+
+ //
+ // Dependency Inject our own focus provider so that we can force the event
+ // dispatcher to deliver events to our component
+ //
+ TestUtils.invokeInstanceMethod("setFocusOwnerProvider", customDispatcher,
+ FocusOwnerProvider.class, focusProvider);
+
+ return (KeyEventDispatcher) customDispatcher;
}
private static class TestFocusOwnerProvider implements FocusOwnerProvider {
diff --git a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/ModifiedPcodeThread.java b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/ModifiedPcodeThread.java
index efcb48dd9d..5e750d609d 100644
--- a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/ModifiedPcodeThread.java
+++ b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/ModifiedPcodeThread.java
@@ -34,6 +34,7 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
import ghidra.util.Msg;
+import ghidra.util.classfinder.ClassSearcher;
/**
* A p-code thread which incorporates per-architecture state modifiers
@@ -232,16 +233,11 @@ public class ModifiedPcodeThread
+ * This addresses the concern that many tools and database entries can refer to custom types,
+ * e.g., options and properties, that may permit an attacker to construct instances of arbitrary
+ * class, those constructors perhaps implementing gadgets that could be used in an exploit
+ * chain.
+ *
+ * The pattern to "mitigate" this is to ensure the found class implements a given interface or
+ * extends from a given class, before invoking a constructor. Ideally, this check can
+ * be applied before class initialization. While much narrower, static initializers may
+ * also provide gadgets. This method implements the pattern which avoids class initialization
+ * until the type has been checked.
+ *
+ * WARNING: Do not pass {@link Object}, a standard JDK interface, or any interface from a
+ * dependency like apache-commons. The purpose of the super type is to narrow the set of
+ * acceptable classes to those we control or that a user has intentionally installed/loaded as a
+ * Ghidra extension. Thus, the static initializers and constructors of all subclasses should be
+ * reviewed carefully.
+ *
+ * @param
- * Examples:
+ * Examples:
*
* /foo/bar/baz/file.jar fully.qualified.ClassName
* /foo/bar/baz/bin fully.qualified.ClassName
diff --git a/Ghidra/Framework/Generic/src/test/java/ghidra/util/classfinder/ClassSearcherTest.java b/Ghidra/Framework/Generic/src/test/java/ghidra/util/classfinder/ClassSearcherTest.java
new file mode 100644
index 0000000000..e3187136e1
--- /dev/null
+++ b/Ghidra/Framework/Generic/src/test/java/ghidra/util/classfinder/ClassSearcherTest.java
@@ -0,0 +1,80 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.util.classfinder;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Constructor;
+
+import org.junit.Test;
+
+public class ClassSearcherTest {
+ public enum Canary {
+ ALIVE, DEAD;
+ }
+
+ public static Canary canary;
+
+ public interface TestSuper {
+ }
+
+ public interface WrongSuper {
+ }
+
+ public static class ClassWithStaticInitializerSideEffects implements TestSuper {
+ static {
+ canary = Canary.DEAD;
+ }
+ }
+
+ /**
+ * Test that our safe(r) version of {@link Class#forName(String)} does not invoke any static
+ * initializer.
+ *
+ * @throws Exception because
+ */
+ @Test
+ public void testForNameSafeNoClinit() throws Exception {
+ canary = Canary.ALIVE;
+
+ Class extends TestSuper> found = ClassSearcher.forNameSafe(
+ "ghidra.util.classfinder.ClassSearcherTest$ClassWithStaticInitializerSideEffects",
+ TestSuper.class, getClass().getClassLoader());
+ assertNotNull(found);
+ assertEquals(Canary.ALIVE, canary);
+ Constructor extends TestSuper> constructor = found.getConstructor();
+ assertEquals(Canary.ALIVE, canary);
+ TestSuper instance = constructor.newInstance();
+ assertNotNull(instance);
+ assertEquals(Canary.DEAD, canary);
+ }
+
+ @Test
+ public void testForNameSafeNoClinitErr() throws Exception {
+ canary = Canary.ALIVE;
+
+ try {
+ ClassSearcher.forNameSafe(
+ "ghidra.util.classfinder.ClassSearcherTest$ClassWithStaticInitializerSideEffects",
+ WrongSuper.class, getClass().getClassLoader());
+ fail("Should not have permitted the class");
+ }
+ catch (ClassCastException e) {
+ // pass
+ }
+ assertEquals(Canary.ALIVE, canary);
+ }
+}
diff --git a/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemePreferences.java b/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemePreferences.java
index 6c8f84d556..e7ee4395a9 100644
--- a/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemePreferences.java
+++ b/Ghidra/Framework/Gui/src/main/java/generic/theme/ThemePreferences.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,6 +20,7 @@ import java.io.IOException;
import ghidra.framework.preferences.Preferences;
import ghidra.util.Msg;
+import ghidra.util.classfinder.ClassSearcher;
/**
* Reads and writes current theme info to preferences
@@ -47,8 +48,9 @@ public class ThemePreferences {
else if (themeId.startsWith(DiscoverableGTheme.CLASS_PREFIX)) {
String className = themeId.substring(DiscoverableGTheme.CLASS_PREFIX.length());
try {
- Class> forName = Class.forName(className);
- return (GTheme) forName.getDeclaredConstructor().newInstance();
+ Class extends GTheme> forName =
+ ClassSearcher.forNameSafe(className, GTheme.class, getClass().getClassLoader());
+ return forName.getDeclaredConstructor().newInstance();
}
catch (Exception e) {
Msg.showError(GTheme.class, null, "Can't Load Previous Theme",
diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/FileOptions.java b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/FileOptions.java
index bf681a3589..829115f528 100644
--- a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/FileOptions.java
+++ b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/FileOptions.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,6 +25,7 @@ import org.apache.commons.io.FilenameUtils;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
+import ghidra.util.classfinder.ClassSearcher;
public class FileOptions extends AbstractOptions {
@@ -53,8 +54,9 @@ public class FileOptions extends AbstractOptions {
public CustomOption readCustomOption(GProperties properties) {
String customOptionClassName = properties.getString("CUSTOM_OPTION_CLASS", null);
try {
- Class> c = Class.forName(customOptionClassName);
- CustomOption customOption = (CustomOption) c.getDeclaredConstructor().newInstance();
+ Class extends CustomOption> c = ClassSearcher.forNameSafe(customOptionClassName,
+ CustomOption.class, getClass().getClassLoader());
+ CustomOption customOption = c.getDeclaredConstructor().newInstance();
customOption.readState(properties);
return customOption;
}
diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/OptionType.java b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/OptionType.java
index e358029ee4..d9a2d7f16a 100644
--- a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/OptionType.java
+++ b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/OptionType.java
@@ -27,6 +27,7 @@ import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;
import ghidra.util.Msg;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.xml.GenericXMLOutputter;
import ghidra.util.xml.XmlUtilities;
@@ -231,8 +232,9 @@ public enum OptionType {
String customOptionClassName =
saveState.getString(CustomOption.CUSTOM_OPTION_CLASS_NAME_KEY, null);
try {
- Class> c = Class.forName(customOptionClassName);
- CustomOption option = (CustomOption) c.getConstructor().newInstance();
+ Class extends CustomOption> c = ClassSearcher.forNameSafe(customOptionClassName,
+ CustomOption.class, OptionType.class.getClassLoader());
+ CustomOption option = c.getConstructor().newInstance();
option.readState(saveState);
return option;
}
diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/ToolOptions.java b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/ToolOptions.java
index c08fb8c46f..4f8582e952 100644
--- a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/ToolOptions.java
+++ b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/ToolOptions.java
@@ -30,6 +30,7 @@ import org.jdom2.Element;
import ghidra.util.*;
import ghidra.util.bean.opteditor.OptionsVetoException;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
/**
@@ -151,9 +152,11 @@ public class ToolOptions extends AbstractOptions {
continue; // shouldn't happen
}
- Class> c = Class.forName(element.getAttributeValue(CLASS_ATTRIBUTE));
- Constructor> constructor = c.getDeclaredConstructor();
- WrappedOption wo = (WrappedOption) constructor.newInstance();
+ Class extends WrappedOption> c =
+ ClassSearcher.forNameSafe(element.getAttributeValue(CLASS_ATTRIBUTE),
+ WrappedOption.class, getClass().getClassLoader());
+ Constructor extends WrappedOption> constructor = c.getDeclaredConstructor();
+ WrappedOption wo = constructor.newInstance();
wo.readState(new SaveState(element));
if (wo instanceof WrappedCustomOption wrappedCustom && !wrappedCustom.isValid()) {
continue;
diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/WrappedCustomOption.java b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/WrappedCustomOption.java
index 79e982438d..f775772871 100644
--- a/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/WrappedCustomOption.java
+++ b/Ghidra/Framework/Gui/src/main/java/ghidra/framework/options/WrappedCustomOption.java
@@ -16,6 +16,7 @@
package ghidra.framework.options;
import ghidra.util.Msg;
+import ghidra.util.classfinder.ClassSearcher;
public class WrappedCustomOption implements WrappedOption {
@@ -36,8 +37,9 @@ public class WrappedCustomOption implements WrappedOption {
String customOptionClassName = saveState.getString("CUSTOM OPTION CLASS", null);
valid = false;
try {
- Class> c = Class.forName(customOptionClassName);
- value = (CustomOption) c.getConstructor().newInstance();
+ Class extends CustomOption> c = ClassSearcher.forNameSafe(customOptionClassName,
+ CustomOption.class, getClass().getClassLoader());
+ value = c.getConstructor().newInstance();
value.readState(saveState);
valid = true;
}
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/ToolUtils.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/ToolUtils.java
index cad16dcc4b..568bad7d20 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/ToolUtils.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/ToolUtils.java
@@ -25,10 +25,13 @@ import org.jdom2.*;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;
+import com.sun.source.util.Plugin;
+
import ghidra.framework.model.ProjectManager;
import ghidra.framework.model.ToolTemplate;
import ghidra.framework.project.tool.GhidraToolTemplate;
import ghidra.util.*;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
import ghidra.util.xml.GenericXMLOutputter;
import ghidra.util.xml.XmlUtilities;
@@ -175,7 +178,7 @@ public class ToolUtils {
// check to see if we can still find the plugin class (it may have
// been removed)
try {
- Class.forName(value);
+ ClassSearcher.forNameSafe(value, Plugin.class, ToolUtils.class.getClassLoader());
}
catch (Throwable t) {
// oh well, leave it out
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginUtils.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginUtils.java
index 92a690fa93..dd8ce1aa99 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginUtils.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/util/PluginUtils.java
@@ -85,11 +85,8 @@ public class PluginUtils {
}
}
- Class> tmpClass = Class.forName(pluginClassName);
- if (!Plugin.class.isAssignableFrom(tmpClass)) {
- throw new PluginException(
- "Class " + pluginClassName + " is not derived from Plugin");
- }
+ Class extends Plugin> tmpClass = ClassSearcher.forNameSafe(pluginClassName,
+ Plugin.class, PluginUtils.class.getClassLoader());
return tmpClass.asSubclass(Plugin.class);
}
catch (ClassNotFoundException e) {
@@ -134,8 +131,8 @@ public class PluginUtils {
}
if (defaultProviderClassName != null) {
try {
- Class> tmpClass = Class.forName(defaultProviderClassName);
- return tmpClass.asSubclass(Plugin.class);
+ return ClassSearcher.forNameSafe(defaultProviderClassName, Plugin.class,
+ PluginUtils.class.getClassLoader());
}
catch (ClassCastException cce) {
Msg.error(PluginUtils.class,
@@ -145,7 +142,6 @@ public class PluginUtils {
catch (ClassNotFoundException e) {
throw new AssertException(
"default provider class for " + serviceClass.getName() + " not found!");
-
}
}
return null;
diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraToolTemplate.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraToolTemplate.java
index 8c1b6395c6..1a76a064aa 100644
--- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraToolTemplate.java
+++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/GhidraToolTemplate.java
@@ -22,11 +22,11 @@ import javax.swing.ImageIcon;
import org.jdom2.Element;
import docking.util.image.ToolIconURL;
-import ghidra.framework.model.Project;
-import ghidra.framework.model.ToolTemplate;
+import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
+import ghidra.util.classfinder.ClassSearcher;
/**
* Implementation for a tool template that has the class names of the
@@ -134,7 +134,8 @@ public class GhidraToolTemplate implements ToolTemplate {
Element elem = (Element) list.get(i);
String className = elem.getAttribute(CLASS_NAME_XML_NAME).getValue();
try {
- dtList.add(Class.forName(className));
+ dtList.add(ClassSearcher
+ .forNameSafe(className, DomainObject.class, getClass().getClassLoader()));
}
catch (ClassNotFoundException e) {
Msg.warn(this, "Tool supported content class not found: " + className);
@@ -181,7 +182,7 @@ public class GhidraToolTemplate implements ToolTemplate {
}
root.addContent(iconElem);
- root.addContent((Element) (toolElement.clone()));
+ root.addContent(toolElement.clone());
return root;
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java
index 812a851428..378be59b64 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java
@@ -47,6 +47,7 @@ import ghidra.program.model.util.ProcessorSymbolType;
import ghidra.sleigh.grammar.SleighPreprocessor;
import ghidra.sleigh.grammar.SourceFileIndexer;
import ghidra.util.*;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.xml.SpecXmlUtils;
@@ -1539,18 +1540,10 @@ public class SleighLanguage implements Language {
return;
}
try {
- Class> helperClass = Class.forName(className);
- if (!ParallelInstructionLanguageHelper.class.isAssignableFrom(helperClass)) {
- Msg.error(this,
- "Invalid Class specified for " +
- GhidraLanguagePropertyKeys.PARALLEL_INSTRUCTION_HELPER_CLASS + " (" +
- helperClass.getName() + "): " + description.getSpecFile());
- }
- else {
- parallelHelper =
- (ParallelInstructionLanguageHelper) helperClass.getDeclaredConstructor()
- .newInstance();
- }
+ Class extends ParallelInstructionLanguageHelper> helperClass =
+ ClassSearcher.forNameSafe(className, ParallelInstructionLanguageHelper.class,
+ getClass().getClassLoader());
+ parallelHelper = helperClass.getDeclaredConstructor().newInstance();
}
catch (Exception e) {
throw new SleighException("Failed to instantiate " +
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
index 0c55620640..492c21d808 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java
@@ -50,6 +50,7 @@ import ghidra.program.model.data.Enum;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Function;
import ghidra.util.*;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ClassTranslator;
import ghidra.util.datastruct.FixedSizeHashMap;
import ghidra.util.exception.*;
@@ -2909,9 +2910,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
String classPath = record.getString(BuiltinDBAdapter.BUILT_IN_CLASSNAME_COL);
String name = record.getString(BuiltinDBAdapter.BUILT_IN_NAME_COL);
try {
- Class> c;
+ Class extends BuiltInDataType> c;
try {
- c = Class.forName(classPath);
+ c = ClassSearcher.forNameSafe(classPath, BuiltInDataType.class,
+ getClass().getClassLoader());
}
catch (ClassNotFoundException | NoClassDefFoundError e) {
// Check the classNameMap.
@@ -2920,14 +2922,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throw e;
}
try {
- c = Class.forName(newClassPath);
+ c = ClassSearcher.forNameSafe(newClassPath, BuiltInDataType.class,
+ getClass().getClassLoader());
}
catch (ClassNotFoundException e1) {
throw e1;
}
}
- BuiltInDataType bdt = (BuiltInDataType) c.getDeclaredConstructor().newInstance();
+ BuiltInDataType bdt = c.getDeclaredConstructor().newInstance();
bdt.setName(name);
bdt.setCategoryPath(catPath);
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/properties/ObjectPropertyMapDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/properties/ObjectPropertyMapDB.java
index 24bf94bbd9..27b233725d 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/properties/ObjectPropertyMapDB.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/properties/ObjectPropertyMapDB.java
@@ -27,6 +27,7 @@ import ghidra.program.model.util.ObjectPropertyMap;
import ghidra.program.util.ChangeManager;
import ghidra.util.Msg;
import ghidra.util.Saveable;
+import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ClassTranslator;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
@@ -132,9 +133,10 @@ public class ObjectPropertyMapDBProgramLocation provides information about a location in a program in the most
@@ -279,7 +280,8 @@ public class ProgramLocation implements Cloneable, Comparable