NationalSecurityAgency/ghidra · error · LSHException

Cannot reset singled executable

Error message

Cannot reset singled executable

What it means

Thrown by ExecutableScorerSingle.setSingleExecutable() when singleExeXref is already >= 0, meaning a singled-out executable has already been established. ExecutableScorerSingle is designed for a one-to-many comparison where exactly one executable is the focus; the single is immutable once set because the scorer allocates a single-row score array and pairs functions relative to it.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/ExecutableScorerSingle.java:58

	 * must be provided.
	 * @param cache is the self-score cacher or null
	 * @throws LSHException for problems initializing the cache
	 */
	public ExecutableScorerSingle(ScoreCaching cache) throws LSHException {
		super();						// Turn on single executable filtering
		singleScore = null;
		scoreCache = cache;
		if (scoreCache == null) {
			scoreCache = new TemporaryScoreCaching();
		}
		simThreshold = scoreCache.getSimThreshold();
		sigThreshold = scoreCache.getSigThreshold();
	}

	@Override
	public void setSingleExecutable(String md5) throws LSHException {
		if (singleExeXref >= 0) {
			throw new LSHException("Cannot reset singled executable");
		}
		super.setSingleExecutable(md5);
	}

	@Override
	public int countSelfScores() {
		Iterator<ExecutableRecord> iter = executableSet.getExecutableRecordSet().iterator();
		int count = 0;
		while (iter.hasNext()) {
			ExecutableRecord exe = iter.next();
			try {
				scoreCache.getSelfScore(exe.getMd5());
				count += 1;
			}
			catch (LSHException e) {
				// Don't increment count
			}
		}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Construct a new ExecutableScorerSingle instance for each new executable you want to compare.
  2. Call resetStorage(simThresh, sigThresh) which nulls singleScore and resets the cache — but note this does NOT reset singleExeXref, so you still need a fresh instance.
  3. Restructure your loop to create the scorer inside the loop body rather than reusing one outside.

Example fix

// before
ExecutableScorerSingle scorer = new ExecutableScorerSingle(cache);
for (String md5 : md5List) {
    scorer.setSingleExecutable(md5); // throws on 2nd iteration
}

// after
for (String md5 : md5List) {
    ExecutableScorerSingle scorer = new ExecutableScorerSingle(cache);
    scorer.setSingleExecutable(md5);
}
Defensive patterns

Strategy: validation

Validate before calling

// Check before calling (singleExeXref is protected; track externally)
boolean alreadySet = (scorer.getSingleExeXref() >= 0); // if exposed
if (!alreadySet) {
    scorer.setSingleExecutable(md5);
}

Try / catch

try {
    scorer.setSingleExecutable(md5);
} catch (LSHException e) {
    if (e.getMessage().contains("Cannot reset")) {
        // create a fresh scorer for the new executable
        scorer = new ExecutableScorerSingle(cache);
        scorer.setSingleExecutable(md5);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling setSingleExecutable(md5) a second time on the same ExecutableScorerSingle instance. The first successful call sets singleExeXref to a non-negative value; any subsequent call throws before reaching the superclass.

Common situations: Reusing an ExecutableScorerSingle instance across multiple queries (e.g. in a loop comparing different executables) without constructing a fresh scorer each iteration. Also occurs when merging two workflows that each set the single executable.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/69abfde14d39d52a. Report an issue: GitHub.