GP-7298: The ProgramLoader and ImportBatchTask now properly validate

loader options
This commit is contained in:
Ryan Kurtz
2026-09-21 11:14:39 -04:00
parent d6192cb3f9
commit 62accc3fa3
4 changed files with 33 additions and 26 deletions

View File

@@ -1665,16 +1665,7 @@ public class HeadlessAnalyzer {
return true;
}
catch (LoadException e) {
Msg.error(this, "The ProgramLoader could not successfully load " + fsrl +
" with the provided import parameters. Please ensure that any specified" +
" processor/cspec arguments are compatible with the loader that is used during" +
" import and try again.");
if (options.loaderClass != null && options.loaderClass != BinaryLoader.class) {
Msg.error(this,
"NOTE: Import failure may be due to missing opinion for \"" +
options.loaderClass.getSimpleName() +
"\". If so, please contact Ghidra team for assistance.");
}
Msg.error(this, "REPORT: " + e.getMessage());
return false;
}
catch (Exception e) {

View File

@@ -629,8 +629,9 @@ public class ProgramLoader {
LoadSpec loadSpec = loadSpecChooser.choose(loaderMap);
if (loadSpec == null) {
String name = Objects.requireNonNullElse(p.getName(), "???");
Msg.info(ProgramLoader.class, "No load spec found for import file: " + name);
throw new LoadException("No load spec found");
throw new LoadException(
"No load spec found. Loader/processor/cspec not compatible with import file: " +
name);
}
return loadSpec;
}
@@ -642,12 +643,12 @@ public class ProgramLoader {
* @param loadSpec The {@link LoadSpec}
* @return The {@link Loader} {@link Option}s, with any loader arguments applied
* @throws LanguageNotFoundException if there was a problem getting the language
* @throws LoadException if the {@link Loader} had {@code null} options
* @throws LoadException if the {@link Loader} had {@code null} or invalid options
*/
private List<Option> getLoaderOptions(ByteProvider p, LoadSpec loadSpec)
throws LanguageNotFoundException, LoadException {
List<Option> options =
loadSpec.getLoader().getDefaultOptions(p, loadSpec, null, false, mirror);
Loader loader = loadSpec.getLoader();
List<Option> options = loader.getDefaultOptions(p, loadSpec, null, false, mirror);
if (options == null) {
throw new LoadException("Cannot load with null options");
}
@@ -673,15 +674,14 @@ public class ProgramLoader {
if (option.getArg() != null && arg.equalsIgnoreCase(option.getArg())) {
Object oldVal = option.getValue();
if (option.parseAndSetValueByType(val, addrFactory)) {
Msg.info(ProgramLoader.class, String.format(
"Successfully applied \"%s\" to \"%s\" (old: \"%s\", new: \"%s\")",
arg, option.getName(), oldVal, val));
Msg.info(ProgramLoader.class,
"Applied \"%s\" to \"%s\" (old: \"%s\", new: \"%s\")".formatted(arg,
option.getName(), oldVal, val));
}
else {
Msg.error(ProgramLoader.class, String.format(
"Failed to apply \"%s\" to \"%s\" (old: \"%s\", bad: \"%s\")", arg,
option.getName(), oldVal, val));
return null;
throw new LoadException(
"Failed to apply \"%s\" to \"%s\" (old: \"%s\", bad: \"%s\")"
.formatted(arg, option.getName(), oldVal, val));
}
foundIt = true;
break;
@@ -691,6 +691,13 @@ public class ProgramLoader {
Msg.warn(ProgramLoader.class, "Skipping unsupported " + arg + " argument");
}
}
String error = loader.validateOptions(p, loadSpec, options, null);
if (error != null) {
throw new LoadException("Options are not valid for %s: %s"
.formatted(loader.getClass().getSimpleName(), error));
}
return options;
}
}

View File

@@ -62,7 +62,7 @@ public interface Loader extends ExtensionPoint, Comparable<Loader> {
SystemUtilities.getBooleanProperty("disable.loader.logging", false);
/**
* A {@link Loader} configuration
* Generic settings acquired from the importer, used to configure the load.
*
* @param provider The bytes to load.
* @param importName The name for the primary {@link Loaded} {@link DomainObject}. Path
@@ -79,7 +79,7 @@ public interface Loader extends ExtensionPoint, Comparable<Loader> {
* @param mirrorFsLayout True if the filesystem layout should be mirrored when
* {@link LoadResults#save(TaskMonitor) saving}; otherwise, false
* @param loadSpec The {@link LoadSpec} to use during load.
* @param options The load options.
* @param options Loader-specific options (could be null).
* @param consumer A reference to the object "consuming" the returned {@link LoadResults}, used
* to ensure the underlying {@link Program}s are only closed when every consumer is done
* with it (see {@link LoadResults#close()}).

View File

@@ -146,10 +146,19 @@ public class ImportBatchTask extends Task {
try {
MessageLog messageLog = new MessageLog();
Project project = AppInfo.getActiveProject();
List<Option> options = getOptionsFor(batchLoadConfig, loadSpec, byteProvider);
if (options != null) {
Loader loader = batchLoadConfig.getLoader();
String error = loader.validateOptions(byteProvider, loadSpec, options, null);
if (error != null) {
Msg.error(this, "Options are not valid for %s: %s"
.formatted(loader.getClass().getSimpleName(), error));
return;
}
}
ImporterSettings settings = new ImporterSettings(byteProvider,
fixupProjectFilename(destInfo.second), project, destInfo.first.getPathname(),
mirrorFs, loadSpec, getOptionsFor(batchLoadConfig, loadSpec, byteProvider),
this, messageLog, monitor);
mirrorFs, loadSpec, options, this, messageLog, monitor);
try (LoadResults<? extends DomainObject> loadResults =
loadSpec.getLoader().load(settings)) {