go-delve/delve · error

nil pointer dereference

Error message

nil pointer dereference

What it means

After evalPointerDeref loads the pointee, the child variable's address (rv.Addr) is 0 — meaning the pointee has no readable backing memory (nil or zero-valued pointer produced without an address). Delve refuses to push an unaddressable pointee and throws 'nil pointer dereference'. This differs from error 68: the pointer expression was not the nilVariable sentinel, but its dereferenced child still has no address.

Source

Thrown at pkg/proc/eval.go:2333

	}

	if len(xev.Children) == 1 {
		// this branch is here to support pointers constructed with typecasts from ints
		xev.Children[0].OnlyAddr = false
		stack.push(&(xev.Children[0]))
		return
	}
	xev.loadPtr()
	if xev.Unreadable != nil {
		val, ok := constant.Uint64Val(xev.Value)
		if ok && val == 0 {
			stack.err = fmt.Errorf("couldn't read pointer: %w", xev.Unreadable)
			return
		}
	}
	rv := &xev.Children[0]
	if rv.Addr == 0 {
		stack.err = errors.New("nil pointer dereference")
		return
	}
	stack.push(rv)
}

// Evaluates expressions &<subexpr>
func (scope *EvalScope) evalAddrOf(op *evalop.AddrOf, stack *evalStack) {
	xev := stack.pop()
	if xev.Addr == 0 || xev.DwarfType == nil {
		stack.err = fmt.Errorf("can not take address of %q", astutil.ExprToString(op.Node.X))
		return
	}

	stack.push(xev.pointerToVariable())
}

func (v *Variable) pointerToVariable() *Variable {
	v.OnlyAddr = true

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Verify the pointer is non-nil before dereferencing: print ptr or print ptr != nil.
  2. If the pointer came from an integer cast, cast a valid address (e.g. obtained via &x) instead of 0.
  3. Step past initialization so the pointer holds a real address.
  4. In tooling, check the dereferenced child's Addr == 0 and display '<nil>' gracefully rather than propagating the error.

Example fix

// before
print *(*T)(unsafe.Pointer(uintptr(p))) // p == 0
// after
condition guard: "p != 0" then
print *(*T)(unsafe.Pointer(uintptr(p)))
Defensive patterns

Strategy: type-guard

Validate before calling

pv, _ := scope.EvalExpression(ptrExpr, cfg)
if pv != nil && pv.Kind == reflect.Ptr && pv.Base == 0 {
    return fmt.Errorf("%s holds a nil/invalid address", ptrExpr)
}

Type guard

func hasPointeeAddress(child *proc.Variable) bool {
    return child != nil && child.Addr != 0
}

Try / catch

_, err := scope.EvalExpression("*"+ptrExpr, cfg)
if err != nil && strings.Contains(err.Error(), "nil pointer dereference") {
    return fmt.Errorf("%s points to nothing (addr 0)", ptrExpr)
}

Prevention

When it happens

Trigger: Dereferencing a pointer constructed from an integer cast (e.g., *(*int)(unsafe.Pointer(uintptr(0)))) or a pointer variable read as 0 from memory where the nilVariable sentinel check did not trigger; DAP/RPC clients expanding a pointer child whose pointee address is 0.

Common situations: Inspecting pointers cast from ints in low-level code; pointer fields zeroed by the program but represented as non-sentinel variables; corrupted memory reads yielding base 0.

Related errors


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