NationalSecurityAgency/ghidra · error · IllegalArgumentException

Memory addresses cannot be associated with a thread

Error message

Memory addresses cannot be associated with a thread

What it means

Thrown by DBTraceSymbolManager.assertValidThreadAddress: a non-null thread may only be paired with a non-memory (i.e. register) address. Memory addresses exist in address spaces that are independent of any thread, so associating one with a thread is a logical error. Register addresses are thread-scoped and are the only addresses that may carry a thread.

Source

Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java:364

			for (AbstractDBTraceSymbolSingleTypeView<?> view : symbolViews.values()) {
				view.invalidateCache();
			}

			if (globalNamespace.isDeleted()) {
				throw new AssertionError();
			}
		}
	}

	// Internal
	public void replaceDataTypes(Map<Long, Long> dataTypeReplacementMap) {
		// Would apply to functions and variables, but those are not supported.
	}

	protected void assertValidThreadAddress(TraceThread thread, Address address) {
		if (thread != null && address.isMemoryAddress()) {
			throw new IllegalArgumentException(
				"Memory addresses cannot be associated with a thread");
		}
	}

	@Override
	public Trace getTrace() {
		return trace;
	}

	@Override
	public AbstractDBTraceSymbol getSymbolByID(long symbolID) {
		if (symbolID == GlobalNamespace.GLOBAL_NAMESPACE_ID) {
			return globalNamespace;
		}
		byte typeID = unpackTypeID(symbolID);
		AbstractDBTraceSymbolSingleTypeView<?> view = symbolViews.get(typeID);
		if (view == null) {
			return null;

View on GitHub (pinned to d5f144c24d)

Solutions

  1. For memory addresses pass thread = null.
  2. Only pass a non-null thread when the address is a register address (address.isRegisterAddress() / address.isMemoryAddress() == false).
  3. Split the call site: memory labels go to the no-thread overload, register symbols to the thread-scoped one.

Example fix

// before
symMgr.createLabel(span, memAddr, name, ns, SourceType.USER, thread /* non-null */);

// after
TraceThread t = memAddr.isMemoryAddress() ? null : thread;
symMgr.createLabel(span, memAddr, name, ns, SourceType.USER, t);
Defensive patterns

Strategy: validation

Validate before calling

TraceThread t = (thread != null && address.isMemoryAddress()) ? null : thread;
symMgr.createLabel(span, address, name, ns, source, t);

Type guard

static boolean threadAddressValid(TraceThread thread, Address address) {
    return thread == null || !address.isMemoryAddress();
}

Prevention

When it happens

Trigger: Creating a symbol (label, variable, etc.) with a thread argument while passing a memory-space Address (address.isMemoryAddress() == true), e.g. a register-space address was expected but a memory address was supplied.

Common situations: Confusing register-context symbols with memory labels; passing a register Address that is actually a memory-mapped register; auto-wiring a thread into every symbol creation call regardless of address space.

Related errors


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