NationalSecurityAgency/ghidra · error · IOException

GhidraRandomAccessFile is closed

Error message

GhidraRandomAccessFile is closed

What it means

GRandomAccessFile maintains an 'open' flag set false by close(). Every mutating/reading operation routes through checkOpen(), which throws this IOException if the instance has already been closed. It is the standard use-after-close guard for a buffered RandomAccessFile wrapper.

Source

Thrown at GPL/DMG/src/dmg/java/mobiledevices/dmg/ghidra/GRandomAccessFile.java:31

 * This implementation relies on java.net.RandomAccessFile,
 * but adds buffering to limit the amount.
 */
public class GRandomAccessFile {
	private static final byte[] EMPTY = new byte[0];
	private static final int BUFFER_SIZE = 0x100000;

	private RandomAccessFile randomAccessFile;
	private byte[] buffer = EMPTY;
	private long bufferOffset = 0;
	private long bufferFileStartIndex = 0;
	private byte[] lastbuffer = EMPTY;
	private long lastbufferOffset = 0;
	private long lastbufferFileStartIndex = 0;
	private boolean open = false;

	private void checkOpen() throws IOException {
		if (!open) {
			throw new IOException("GhidraRandomAccessFile is closed");
		}
	}

	/**
	 * Creates a random access file stream to read from, and optionally to
	 * write to, the file specified by the {@link File} argument.  A new {@link
	 * FileDescriptor} object is created to represent this file connection.
	 *
	 * <p>
	 * This implementation relies on java.net.RandomAccessFile,
	 * but adds buffering to limit the amount.
	 * <p>
	 * 
	 * <a name="mode"><p> The <tt>mode</tt> argument specifies the access mode
	 * in which the file is to be opened.  The permitted values and their
	 * meanings are:
	 *
	 * <blockquote><table summary="Access mode permitted values and meanings">

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Audit the lifecycle: ensure no reads/seeks happen after the close() that owns this GRandomAccessFile.
  2. Move the close() to the true end of use, or stop retaining references past close.
  3. Use try-with-resources scoped tightly around the read loop so close runs only after all access completes.
  4. Null out references after close to surface accidental reuse as an NPE earlier in the chain.

Example fix

// before
graf.close();
// ... later, in error path:
graf.seek(pos);

// after - ensure no access after close, scope the resource
try (GRandomAccessFile graf = new GRandomAccessFile(file, mode)) {
    graf.seek(pos);
    // ... all reads here
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-call validation possible; track ownership centrally.
// Optional: wrap access in a guard that checks an application-level 'closed' flag
if (graf == null) throw new IllegalStateException("GRandomAccessFile reference is null (already released)");
graf.seek(pos);

Type guard

// Not a type guard per se, but a lifecycle wrapper:
class SafeRandomAccessFile {
    private final GRandomAccessFile inner;
    private volatile boolean closed = false;
    synchronized void close() throws IOException { closed = true; inner.close(); }
    void seek(long pos) throws IOException {
        if (closed) throw new IOException("already closed");
        inner.seek(pos);
    }
}

Try / catch

try {
    graf.seek(pos);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().contains("is closed")) {
        // Use-after-close: do not retry; re-open or fail upward with context
        throw new IOException("Attempted to use GRandomAccessFile after close", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling any operation (read, seek, write, length, etc.) on a GRandomAccessFile after close() was invoked. Commonly happens when the owning reader/provider is closed but a reference to the underlying file is still held and used, or in error-handling paths that close early then continue.

Common situations: Closing a DmgFileReader/ByteProvider in a finally block but then retrying an operation; nested resource management where the outer close invalidates an inner handle still in use; a try-with-resources that scoped too widely; double-close across multiple owners of the same handle.

Related errors


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