NationalSecurityAgency/ghidra · error · IllegalStateException

More than one state is present in

Error message

More than one state is present in 

What it means

Thrown by InternalTraceMemoryOperations.requireOne when TraceMemoryOperations.oneState returns null for a register's address range. oneState returns null when the register's conventional address range is covered by memory-state entries that are not all the same state, or when the entries do not completely cover the range. This indicates the register spans bytes with heterogeneous memory states (e.g. part KNOWN, part UNKNOWN), so no single uniform state can be reported for the whole register.

Source

Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/InternalTraceMemoryOperations.java:43

import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.TraceMemoryOperations;
import ghidra.trace.model.memory.TraceMemoryState;
import ghidra.trace.util.TraceRegisterUtils;
import ghidra.util.LockHold;

@Internal
public interface InternalTraceMemoryOperations extends TraceMemoryOperations {

	static TraceMemoryState requireOne(AddressRange range,
			Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> states, Register register) {
		TraceMemoryState state =
			TraceMemoryOperations.oneState(range, states);
		if (state == null) {
			throw new IllegalStateException("More than one state is present in " + register);
		}
		return state;
	}

	/**
	 * For register mapping conventions
	 * 
	 * @return the address space
	 */
	AddressSpace getSpace();

	ReadWriteLock getLock();

	@Override
	default void setState(TracePlatform platform, long snap, Register register,
			TraceMemoryState state) {
		AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
		setState(snap, range, state);

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Use TraceMemoryOperations.oneState yourself before calling requireOne and handle a null (non-uniform) result gracefully instead of requiring a single state.
  2. Query state on the smallest sub-register that is fully covered, or query each byte/sub-range separately to find where the state boundary falls.
  3. Ensure the entire register range is written/known before requiring a uniform state (write all bytes or set state for the full conventional range).

Example fix

// before
TraceMemoryState state = memOps.requireOne(range, states, register);

// after
TraceMemoryState state = TraceMemoryOperations.oneState(range, states);
if (state == null) {
    // register spans mixed states; handle per sub-range
    for (var e : states) {
        // inspect e.getKey().getRange() and e.getValue()
    }
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

// Call oneState yourself and handle null (non-uniform state) before requireOne
TraceMemoryState state = TraceMemoryOperations.oneState(range, states);
if (state == null) {
    // register spans mixed memory states; do not call requireOne
    // inspect states per sub-range instead
    return;
}
// safe to use the uniform state

Type guard

// Check that a register range has a uniform state before requiring one
static boolean hasUniformState(AddressRange range,
        Collection<Map.Entry<TraceAddressSnapRange, TraceMemoryState>> states) {
    return TraceMemoryOperations.oneState(range, states) != null;
}

Prevention

When it happens

Trigger: Calling a register-level state operation (e.g. getState on a Register) whose conventional range overlaps multiple memory-state boundaries with differing TraceMemoryState values. This happens when a sub-register or parent register's byte range crosses a region boundary, or when only part of the register has been written/known at the given snap.

Common situations: Inspecting or requiring a uniform memory state for a multi-byte register (e.g. a 64-bit register where only the lower 32 bits were set) in a debugger/emulator trace. Partial register writes in emulator traces that mark sub-registers known but leave the rest unknown. Querying state of a register that overlaps two memory regions.

Related errors


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