go-delve/delve · error · ErrShortRead

short read

Error message

short read

What it means

ErrShortRead is returned by the Windows native backend's ReadMemory when ReadProcessMemory succeeds but copies fewer bytes than the requested buffer size. Delve treats a partial read as an error because variable and instruction reads need the full requested span to be valid.

Source

Thrown at pkg/proc/native/threads_windows.go:125

	if ok, err := t.dbp.Valid(); !ok {
		return 0, err
	}
	if len(data) == 0 {
		return 0, nil
	}
	var count uintptr
	err := _WriteProcessMemory(t.dbp.os.hProcess, uintptr(addr), &data[0], uintptr(len(data)), &count)
	if err != nil {
		return 0, err
	}
	// On ARM64 the instruction and data caches are not coherent,
	// WriteProcessMemory only updates the data cache so we must flush
	// the instruction cache explicitly. On x86/amd64 this is a no-op.
	_ = _FlushInstructionCache(t.dbp.os.hProcess, uintptr(addr), uintptr(len(data)))
	return int(count), nil
}

var ErrShortRead = errors.New("short read")

func (t *nativeThread) ReadMemory(buf []byte, addr uint64) (int, error) {
	if ok, err := t.dbp.Valid(); !ok {
		return 0, err
	}
	if len(buf) == 0 {
		return 0, nil
	}
	var count uintptr
	err := _ReadProcessMemory(t.dbp.os.hProcess, uintptr(addr), &buf[0], uintptr(len(buf)), &count)
	if err == nil && count != uintptr(len(buf)) {
		err = ErrShortRead
	}
	return int(count), err
}

// SoftExc returns true if this thread received a software exception during the last resume.
func (t *nativeThread) SoftExc() bool {

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Check the pointer/address value being read for corruption before dereferencing it
  2. Reduce the requested read size or read page-by-page, stopping at the first failure
  3. Verify the target process is alive and the debug session is valid (dbp.Valid)
  4. Attach with sufficient privileges (SeDebugPrivilege) so all relevant pages are readable

Example fix

// before
n, err := thread.ReadMemory(buf, badPtr)
// after
n, err := thread.ReadMemory(buf, badPtr)
if err == proc.ErrShortRead {
    buf = buf[:n] // use only the bytes actually read
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check: is the debugged process still valid?
// Delve checks internally via dbp.Valid(); from the RPC layer check process state first.
if !attached || processExited {
    return fmt.Errorf("target not available")
}

Type guard

func isShortRead(err error) bool {
    return errors.Is(err, proc.ErrShortRead)
}

Try / catch

n, err := thread.ReadMemory(buf, addr)
if errors.Is(err, proc.ErrShortRead) {
    // use only the bytes that were read: buf[:n]
    handlePartial(buf[:n])
    return nil
} else if err != nil {
    return err
}

Prevention

When it happens

Trigger: Any ReadMemory call on a Windows thread whose target address range crosses into unmapped or inaccessible memory, so ReadProcessMemory fills only part of buf and returns a short count.

Common situations: Reading past the end of a heap allocation or stack page, reading corrupted pointer values that point outside the process's mapped memory, or inspecting a target whose memory layout changed (process dying, guard pages).

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/47a6a7ae13393c77. Report an issue: GitHub.