NationalSecurityAgency/ghidra · error · IllegalArgumentException
data and mask must have same capacity
Error message
data and mask must have same capacity
What it means
Thrown by DBTraceMemorySpace.findBytes() when the data ByteBuffer and the mask ByteBuffer passed to the search have different capacities. The method uses data.capacity() as the expected length and checks mask.capacity() != len when mask is non-null. An IllegalArgumentException (unchecked) signals a caller contract violation: both buffers must have identical capacity for the masked byte search to work.
Source
Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemorySpace.java:891
continue;
}
if (!ByteBufferUtils.maskedEquals(mask, data, read)) {
continue;
}
return addr;
}
return null;
}
@Override
public Address findBytes(long snap, AddressRange range, ByteBuffer data, ByteBuffer mask,
boolean forward, TaskMonitor monitor) {
// ProgramDB uses the naive method with some skipping, so here we go....
// TODO: This could be made faster by skipping over non-initialized blocks
// TODO: DFA method would be complicated by masks....
int len = data.capacity();
if (mask != null && mask.capacity() != len) {
throw new IllegalArgumentException("data and mask must have same capacity");
}
if (len == 0 ||
range.getLength() > 0 /*treat length unsigned*/ && range.getLength() < len) {
return null;
}
// LATER: Worry about the viewport, too?
// This will reduce the search to ranges that have any once-known value at the snap.
// NOTE: Potentially costly to pre-compute the set concretely
AddressSet known = new AddressSet(
stateMapSpace.getAddressSetView(Lifespan.at(snap), StatePredicate.IS_KNOWN))
.intersect(new AddressSet(range));
monitor.initialize(known.getNumAddresses());
for (AddressRange knownRange : known.getAddressRanges(forward)) {
Address found = doFindBytesInRange(snap, knownRange, data, mask, forward, monitor);
if (found != null) {
return found;
}View on GitHub (pinned to d5f144c24d)
Solutions
- Ensure both ByteBuffer objects have the same capacity: allocate mask with ByteBuffer.allocate(data.capacity()) or verify sizes before calling.
- Use a helper to construct matched data/mask pairs from a byte pattern and mask string.
- If searching without a mask, pass null for the mask parameter instead of an empty or mismatched buffer.
Example fix
// before ByteBuffer data = ByteBuffer.wrap(patternBytes); ByteBuffer mask = ByteBuffer.wrap(maskBytes); // different length! Address found = memory.findBytes(snap, range, data, mask, true, monitor); // after assert patternBytes.length == maskBytes.length; ByteBuffer data = ByteBuffer.wrap(patternBytes); ByteBuffer mask = ByteBuffer.wrap(maskBytes); Address found = memory.findBytes(snap, range, data, mask, true, monitor);
Defensive patterns
Strategy: validation
Validate before calling
// Validate buffer capacities before searching
ByteBuffer data = /* pattern */;
ByteBuffer mask = /* mask or null */;
if (mask != null && mask.capacity() != data.capacity()) {
throw new IllegalStateException(
"data capacity (" + data.capacity() + ") != mask capacity (" + mask.capacity() + ")");
}
Address found = memory.findBytes(snap, range, data, mask, true, monitor); Prevention
- Always allocate data and mask buffers with the same capacity.
- Pass null for mask when no masking is needed.
- Add an assertion: assert mask == null || mask.capacity() == data.capacity().
When it happens
Trigger: Calling findBytes(snap, range, data, mask, forward, monitor) where data.capacity() != mask.capacity(). For example, passing a 4-byte pattern buffer with a 1-byte mask, or vice versa. The check fires immediately before the search begins.
Common situations: Constructing search patterns programmatically where the data and mask buffers are allocated independently with different sizes. Copying a mask from one search context to another with a different data length. Off-by-one in buffer allocation.
Related errors
- Length must match the register
- Byte arrays cannot exceed length of variable
- Platform and prototype disagree in language
- Cannot delete an undefined code unit
- Cannot modify lifespan of default data unit
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/f352e4a3bc10aa19.
Report an issue: GitHub.