NationalSecurityAgency/ghidra · error · UnsupportedOperationException

TODO: Unoptimized byte diff

Error message

TODO: Unoptimized byte diff

What it means

An explicit UnsupportedOperationException marking an unimplemented code path in trace-view byte differencing. When the memory map reports blockSize == 0 (no block-optimized storage), the byte-by-byte comparison algorithm is not implemented, so the diff aborts.

Source

Thrown at Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/diff/DebuggerTraceViewDiffPlugin.java:558

		TraceMemoryManager mm = trace.getMemoryManager();

		AddressSetView known1 = mm.getAddressesWithState(snap1, StatePredicate.IS_KNOWN);
		AddressSetView known2 = mm.getAddressesWithState(snap2, StatePredicate.IS_KNOWN);

		//AddressSet knownEither = known1.union(known2);
		AddressSet knownBoth = known1.intersect(known2); // Will need byte-by-byte examination

		// Symmetric difference in state counts as difference?
		// TODO: Should that be togglable?

		AddressSet diff = new AddressSet(); //knownEither;
		//knownEither = null; // Don't need knownEither anymore. Avoid accidental use
		//diff.delete(knownBoth);

		int blockSize = mm.getBlockSize();
		if (blockSize == 0) {
			throw new UnsupportedOperationException("TODO: Unoptimized byte diff");
		}
		ByteBuffer buf1 = ByteBuffer.allocate(blockSize);
		ByteBuffer buf2 = ByteBuffer.allocate(blockSize);

		while (!knownBoth.isEmpty()) {
			Address next = knownBoth.getMinAddress();
			Long mrs1 = mm.getSnapOfMostRecentChangeToBlock(snap1, next);
			Long mrs2 = mm.getSnapOfMostRecentChangeToBlock(snap2, next);
			if (Objects.equals(mrs1, mrs2)) {
				knownBoth.delete(blockFor(blockSize, next));
				continue;
			}

			int len = lenRemainsBlock(blockSize, next.getOffset());
			buf1.clear();
			buf1.limit(len);
			if (len != mm.getBytes(snap1, next, buf1)) {
				throw new AssertionError("Read failed");

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Use snapshots/traces whose memory manager supports block-optimized storage (non-zero block size).
  2. Run the diff against a recorded emulator target rather than a synthetic/empty trace.
  3. File a feature request / contribute the unoptimized byte-diff path upstream (it is a TODO).
  4. Fall back to a manual byte comparison via TraceMemoryBuffer over the knownBoth address set.

Example fix

// before
int blockSize = mm.getBlockSize();
if (blockSize == 0) {
    throw new UnsupportedOperationException("TODO: Unoptimized byte diff");
}

// after (caller-side guard)
if (mm.getBlockSize() == 0) {
    Msg.warn(this, "Byte diff unavailable: memory lacks block optimization");
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

boolean supported = trace.getMemoryManager().getBlockSize() != 0;

Type guard

static boolean diffSupported(TraceMemoryManager mm) {
    return mm.getBlockSize() != 0;
}

Try / catch

try {
    plugin.diffSnapshots(snap1, snap2);
} catch (UnsupportedOperationException e) {
    Msg.showWarn(this, null, "Diff unavailable", e.getMessage());
}

Prevention

When it happens

Trigger: Invoking the trace-view diff on two snapshots whose TraceMemoryManager's block size is 0 (memory backed by an implementation without block-change tracking).

Common situations: Comparing traces or snapshots that use a memory storage backend without block optimization; diffing newly-created or synthetic traces; traces imported from formats that do not populate block metadata.

Related errors


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