NationalSecurityAgency/ghidra · critical · IOException

compressed memory buffer is corrupt

Error message

compressed memory buffer is corrupt

What it means

Thrown by DBTraceMemoryBufferEntry.doGetCompressedBytes() when reading from a GZIP-compressed memory buffer and the decompressed stream returns fewer bytes (amt) than the requested length (len). The method wraps the buffer in a GZIPInputStream and reads len bytes at a computed offset; if amt != len, the compressed buffer is internally inconsistent. An IOException (checked) indicates the compressed data is truncated or corrupt.

Source

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

		assert isSane(srcOffset, len, blockNum);
		if (compressed) {
			return doGetCompressedBytes(buf, srcOffset, len, blockNum);
		}
		buffer.get((blockNum << DBTraceMemorySpace.BLOCK_SHIFT) + srcOffset, buf.array(),
			buf.arrayOffset() + buf.position(), len);
		buf.position(buf.position() + len);
		return len;
	}

	protected int doGetCompressedBytes(ByteBuffer buf, int srcOffset, int len, int blockNum)
			throws IOException {
		try (InputStream is = new GZIPInputStream(new DBBufferInputStream(buffer))) {
			is.skip((blockNum << DBTraceMemorySpace.BLOCK_SHIFT) + srcOffset);
			int amt = is.read(buf.array(), buf.arrayOffset() + buf.position(), len);
			buf.position(buf.position() + amt);
			if (amt != len) {
				// There should always be enough
				throw new IOException("compressed memory buffer is corrupt");
			}
			return len;
		}
	}

	protected void doGetBlock(int blockNum, byte[] data)
			throws IndexOutOfBoundsException, IOException {
		assert isInUse(blockNum);
		if (compressed) {
			doGetCompressedBlock(blockNum, data);
		}
		buffer.get(blockNum << DBTraceMemorySpace.BLOCK_SHIFT, data);
	}

	protected void doGetCompressedBlock(int blockNum, byte[] data) throws IOException {
		try (InputStream is = new GZIPInputStream(new DBBufferInputStream(buffer))) {
			is.skip(blockNum << DBTraceMemorySpace.BLOCK_SHIFT);
			int amt = is.read(data);

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Restore the trace database from a backup taken before the corruption.
  2. Re-record the trace from the debugging session if a backup is unavailable.
  3. If only specific memory blocks are affected, clear and re-record those regions.
  4. Investigate storage integrity (disk health, filesystem checks) to prevent recurrence.
Defensive patterns

Strategy: fallback

Try / catch

try {
    int amt = memory.getBytes(snap, addr, buf);
} catch (IOException e) {
    if (e.getMessage().contains("compressed memory buffer is corrupt")) {
        // corrupted compressed buffer; restore from backup or re-record
        logger.severe("Corrupt compressed buffer at " + addr + ": " + e.getMessage());
    }
}

Prevention

When it happens

Trigger: Calling doGetCompressedBytes() (via getBytes or doGetBlock) on a DBTraceMemoryBufferEntry flagged as compressed, where the underlying GZIP data stream is shorter than expected. This happens when the compressed buffer was partially written, truncated during save, or corrupted on disk.

Common situations: Database corruption after a crash or improper shutdown during a save operation. Disk space exhaustion that truncated a write. Partial trace database copy or transfer. Version or format incompatibility in the compression scheme.

Related errors


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