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 a442503e5a..fbd30a53e1 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 @@ -1028,6 +1028,7 @@ public class HeadlessAnalyzer { if (abortProcessing) { Msg.info(this, "Processing aborted as a result of pre-script."); + mgr.dispose(); return !deleteProgram; } @@ -1058,6 +1059,7 @@ public class HeadlessAnalyzer { // If no further scripts, just return the current program disposition if (options.postScripts.isEmpty()) { + mgr.dispose(); return !deleteProgram; } @@ -1125,6 +1127,7 @@ public class HeadlessAnalyzer { } + mgr.dispose(); return !deleteProgram; } @@ -1222,7 +1225,6 @@ public class HeadlessAnalyzer { if (options.commit) { - AutoAnalysisManager.getAnalysisManager(program).dispose(); program.release(this); program = null; @@ -1255,7 +1257,6 @@ public class HeadlessAnalyzer { finally { if (program != null) { - AutoAnalysisManager.getAnalysisManager(program).dispose(); program.release(this); program = null; } @@ -1415,7 +1416,7 @@ public class HeadlessAnalyzer { return p; } - private boolean checkOverwrite(Loaded loaded) throws IOException { + private boolean checkOverwrite(Loaded loaded) throws IOException { DomainFolder folder = project.getProjectData().getFolder(loaded.getProjectFolderPath()); if (folder == null) { return true; @@ -1543,7 +1544,7 @@ public class HeadlessAnalyzer { // Perform the load. // Note that loading 1 file may result in more than 1 thing getting loaded. - LoadResults loadResults = null; + LoadResults loadResults = null; try { loadResults = ProgramLoader.builder() .source(fsrl) @@ -1554,37 +1555,40 @@ public class HeadlessAnalyzer { .compiler(options.compilerSpec) .loaders(options.loaderClass) .loaderArgs(options.loaderArgs) - .load(); + .loadAll(); Msg.info(this, "IMPORTING: Loaded " + (loadResults.size() - 1) + " additional files"); - // Make sure we are allowed to save ALL programs to the project. If not, save none and - // fail. + // Make sure we are allowed to save ALL domain objects to the project. + // If not, save none and fail. if (!options.readOnly) { - for (Loaded loaded : loadResults) { + for (Loaded loaded : loadResults) { if (!checkOverwrite(loaded)) { return false; } } } - // Check if there are defined memory blocks in the primary program. - // Abort if not (there is nothing to work with!). - Loaded primary = loadResults.getPrimary(); - if (primary.check(p -> p.getMemory().getAllInitializedAddressSet().isEmpty())) { - Msg.error(this, "REPORT: Error: No memory blocks were defined for file " + fsrl); - return false; - } - - // Analyze the primary program, and determine if we should save. - // TODO: Analyze non-primary programs (GP-2965). - Program primaryProgram = primary.getDomainObject(this); - boolean doSave; + boolean doSave = !options.readOnly; + Loaded primary = loadResults.getPrimary(); + DomainObject primaryDomainObject = primary.getDomainObject(this); try { - doSave = analyzeProgram(fsrl.toString(), primaryProgram) && !options.readOnly; + if (primaryDomainObject instanceof Program primaryProgram) { + // Check if there are defined memory blocks in the primary program. + // Abort if not (there is nothing to work with!). + if (primaryProgram.getMemory().getAllInitializedAddressSet().isEmpty()) { + Msg.error(this, + "REPORT: Error: No memory blocks were defined for file " + fsrl); + return false; + } + + // Analyze the primary program, and determine if we should save. + // TODO: Analyze non-primary programs (GP-2965). + doSave = analyzeProgram(fsrl.toString(), primaryProgram) && doSave; + } } finally { - primaryProgram.release(this); + primaryDomainObject.release(this); } // The act of marking the program as temporary by a script will signal @@ -1605,8 +1609,8 @@ public class HeadlessAnalyzer { } // Save - for (Loaded loaded : loadResults) { - if (!loaded.check(Program::isTemporary)) { + for (Loaded loaded : loadResults) { + if (!loaded.check(DomainObject::isTemporary)) { try { DomainFile domainFile = loaded.save(TaskMonitor.DUMMY); Msg.info(this, String.format("REPORT: Save succeeded for: %s (%s)", loaded, @@ -1630,11 +1634,8 @@ public class HeadlessAnalyzer { // Commit changes if (options.commit) { - for (Loaded loaded : loadResults) { - if (!loaded.check(Program::isTemporary)) { - if (loaded == primary) { - AutoAnalysisManager.getAnalysisManager(primaryProgram).dispose(); - } + for (Loaded loaded : loadResults) { + if (!loaded.check(DomainObject::isTemporary)) { loaded.close(); // we need to close before committing commitProgram(loaded.getSavedDomainFile()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/ProgramLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/ProgramLoader.java index 025e1850af..7a59ddb169 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/ProgramLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/ProgramLoader.java @@ -464,6 +464,67 @@ public class ProgramLoader { @Deprecated(since = "12.0", forRemoval = true) LoadResults load(Object consumer) throws IOException, LanguageNotFoundException, CancelledException, VersionException, LoadException { + + LoadResults loadResults = loadAll(consumer); + + // Filter out and release non-Programs + List> loadedPrograms = new ArrayList<>(); + for (Loaded loaded : loadResults) { + if (Program.class.isAssignableFrom(loaded.getDomainObjectType())) { + loadedPrograms.add((Loaded) loaded); + } + else { + try { + loaded.close(); + } + catch (Exception e) { + throw new IOException(e); + } + } + } + if (loadedPrograms.isEmpty()) { + throw new LoadException("Domain objects were loaded, but none were Programs"); + } + return new LoadResults<>(loadedPrograms); + } + + /** + * Loads the specified {@link #source(ByteProvider) source} with this {@link Builder}'s + * current configuration + * + * @return The {@link LoadResults} which contains one or more {@link Loaded} + * {@link DomainObject}s (created but not saved) + * @throws IOException if there was an IO-related problem loading + * @throws LanguageNotFoundException if there was a problem getting the language + * @throws CancelledException if the operation was cancelled + * @throws VersionException if there was an issue with database versions, probably due to a + * failed language upgrade + * @throws LoadException if there was a problem loading + */ + public LoadResults loadAll() throws IOException, + LanguageNotFoundException, CancelledException, VersionException, LoadException { + return loadAll(this); + } + + /** + * Loads the specified {@link #source(ByteProvider) source} with this {@link Builder}'s + * current configuration + * + * @param consumer A reference to the object "consuming" the returned {@link LoadResults}, + * used to ensure the underlying {@link DomainObject}s are only closed when every consumer + * is done with it (see {@link LoadResults#close()}). + * @return The {@link LoadResults} which contains one or more {@link Loaded} + * {@link DomainObject}s (created but not saved) + * @throws IOException if there was an IO-related problem loading + * @throws LanguageNotFoundException if there was a problem getting the language + * @throws CancelledException if the operation was cancelled + * @throws VersionException if there was an issue with database versions, probably due to a + * failed language upgrade + * @throws LoadException if there was a problem loading + */ + @Deprecated(since = "12.1", forRemoval = true) + public LoadResults loadAll(Object consumer) throws IOException, + LanguageNotFoundException, CancelledException, VersionException, LoadException { try (ByteProvider p = getSourceAsProvider()) { LoadSpec loadSpec = getLoadSpec(p); @@ -501,25 +562,7 @@ public class ProgramLoader { Msg.info(ProgramLoader.class, "Additional info:\n" + log); } - // Filter out and release non-Programs - List> loadedPrograms = new ArrayList<>(); - for (Loaded loaded : loadResults) { - if (Program.class.isAssignableFrom(loaded.getDomainObjectType())) { - loadedPrograms.add((Loaded) loaded); - } - else { - try { - loaded.close(); - } - catch (Exception e) { - throw new IOException(e); - } - } - } - if (loadedPrograms.isEmpty()) { - throw new LoadException("Domain objects were loaded, but none were Programs"); - } - return new LoadResults<>(loadedPrograms); + return loadResults; } }