NationalSecurityAgency/ghidra · error · PcodeExecutionException

Cannot evaluate unique $U

Error message

Cannot evaluate unique $U%x:%d

What it means

Thrown (unchecked PcodeExecutionException) by the default evaluateUnique when a unique-space varnode ($U offset) is evaluated as a leaf. Uniques are p-code temporaries that only have meaning through their defining op; the base implementation deliberately rejects leaf evaluation of them because a unique has no independent value.

Solutions

  1. Ensure unique varnodes are always reached via their defining op so the result is cached before leaf evaluation (evaluate defining ops in topological/data-flow order).
  2. Override evaluateUnique in your subclass to return a symbolic/unknown value instead of throwing, if leaf evaluation of uniques is expected in your analysis.
  3. Pre-populate the 'already' cache with modelled values for the uniques you will encounter.

Example fix

// before: default evaluateUnique throws
// (occurs when a $U varnode is reached as a leaf)

// after: override in your evaluator subclass to model uniques symbolically
@Override
protected T evaluateUnique(long offset, int size) {
    return model.newUnique(offset, size); // symbolic value, no throw
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure uniques are reached via their defining op, not as a leaf
PcodeOp def = vn.getDef();
boolean isUniqueLeaf = vn.isUniqueAddress() && (def == null || !cache.containsKey(vn));
if (isUniqueLeaf) {
    // will throw by default; override evaluateUnique or seed the cache first
}

Try / catch

try {
    T val = evaluator.evaluateVarnode(program, vn, cache);
} catch (PcodeExecutionException e) {
    if (e.getMessage().startsWith("Cannot evaluate unique")) { /* model symbolically */ }
    else throw e;
}

Prevention

When it happens

Trigger: The evaluator's cache ('already') lacks an entry for a unique varnode and evaluation reaches it as a leaf instead of through its defining p-code op. This indicates the unique's defining op was not evaluated first, or the varnode was reached out of order.

Common situations: Symbolic/abstract execution that follows data flow but skips the op that defines a temporary; analyzing partial p-code where the defining op for a $U varnode is outside the examined window; a custom evaluator that doesn't seed the cache from defining ops.

Related errors


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

Appendix: source

Thrown at Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/eval/AbstractVarnodeEvaluator.java:281

	 * @param address the address of the variable
	 * @param size the size of the variable in bytes
	 * @return the value
	 */
	protected abstract T evaluateMemory(Address address, int size);

	/**
	 * Evaluate a unique variable
	 * 
	 * <p>
	 * This is only invoked when trying to evaluate a leaf, which should never occur for a unique
	 * variable. Thus, by default, this throws a {@link PcodeExecutionException}.
	 * 
	 * @param offset the offset of the variable
	 * @param size the size of the variable in bytes
	 * @return the value
	 */
	protected T evaluateUnique(long offset, int size) {
		throw new PcodeExecutionException(
			String.format("Cannot evaluate unique $U%x:%d", offset, size));
	}

	/**
	 * Evaluate a variable with an abstract offset
	 * 
	 * <p>
	 * The three parameters {@code space}, {@code offset}, and {@code size} imitate the varnode
	 * triple, except that the offset is abstract. This is typically invoked for a
	 * {@link PcodeOp#LOAD}, i.e., a dereference.
	 * 
	 * @param program the program defining the static context
	 * @param space the address space of the variable
	 * @param offset the offset of the variable
	 * @param size the size of the variable in bytes
	 * @param already a cache of already-evaluated varnodes and their values
	 * @return the value
	 */

View on GitHub (pinned to d5f144c24d)