Understanding the Error
The invalid memory address error is a segmentation fault that occurs when your Go program tries to read from or write to an invalid memory location:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x4b3c2a]The addr field shows the memory address attempted. Small addresses (like 0x0, 0x8, 0x20) typically indicate nil pointer access. Larger addresses might suggest corrupted pointers or use-after-free scenarios.
Root Causes and Solutions
Cause 1: Nil Pointer Dereference
Most common cause - accessing a nil pointer:
```go type Server struct { config *Config }
func (s *Server) Start() { // s.config is nil fmt.Println(s.config.Port) // SIGSEGV! } ```
Solution:
func (s *Server) Start() error {
if s.config == nil {
return errors.New("server config is nil")
}
fmt.Println(s.config.Port)
return nil
}Cause 2: Method on Nil Receiver
Go allows calling methods on nil receivers, but you must handle it:
Problematic: ```go type User struct { name string }
func (u *User) GetName() string { return u.name // Panics if u is nil } ```
Safe version:
``go
func (u *User) GetName() string {
if u == nil {
return "" // or return "unknown"
}
return u.name
}
Cause 3: Unsafe Pointer Operations
Using the unsafe package incorrectly:
```go import "unsafe"
func main() { var i int = 42 p := unsafe.Pointer(uintptr(unsafe.Pointer(&i)) + 100) // Invalid offset! fmt.Println(*(*int)(p)) // SIGSEGV! } ```
Solution - Avoid unsafe when possible, or validate:
func main() {
var i int = 42
// If you must use unsafe, ensure validity
p := unsafe.Pointer(&i)
// Stay within the original allocation
val := *(*int)(p)
fmt.Println(val) // 42
}Cause 4: Cgo Memory Issues
When using C libraries through cgo:
```go /* #include <stdlib.h> */ import "C" import "unsafe"
func main() { ptr := C.malloc(C.size_t(10)) // Missing null check C.free(ptr) C.free(ptr) // Double free - undefined behavior } ```
Solution:
```go func main() { ptr := C.malloc(C.size_t(10)) if ptr == nil { panic("malloc failed") } defer C.free(ptr) // Use defer to ensure single free
// Use the memory... } ```
Cause 5: Use After Close/Free
```go func main() { data := make([]int, 10) ptr := &data[0]
// data goes out of scope, ptr becomes invalid data = nil
fmt.Println(*ptr) // May crash! } ```
Solution:
```go func main() { data := make([]int, 10) // Keep data alive as long as you need ptr ptr := &data[0]
fmt.Println(*ptr) // Safe // Don't reassign data while ptr is in use } ```
Advanced Debugging
Using Delve Debugger
```bash # Start delve dlv debug ./main.go
# Set breakpoints (dlv) break main.go:25 (dlv) continue
# When breakpoint hits, inspect variables (dlv) print ptr (dlv) print *ptr
# Check goroutine information (dlv) goroutines ```
Enable Core Dumps
```bash # Enable core dumps ulimit -c unlimited
# Run your program ./my-program
# After crash, analyze core dlv core ./my-program core ```
Inside delve with core file:
``
(dlv) goroutine 1
(dlv) bt
(dlv) frame 0
(dlv) locals
Address Sanitizer (Go 1.18+)
```bash # Build with address sanitizer go build -asan main.go
# Run - will detect memory issues ./main ```
Verification and Testing
Write Tests That Catch Issues
```go func TestNilSafeMethods(t *testing.T) { var u *User = nil
// This should not panic name := u.GetName() if name != "" { t.Errorf("expected empty name for nil user, got %s", name) } }
func TestInvalidInputs(t *testing.T) { s := &Server{} err := s.Start() if err == nil { t.Error("expected error for nil config") } } ```
Run with Race Detector
go test -race ./...
go run -race main.goFuzz Testing (Go 1.18+)
func FuzzParser(f *testing.F) {
f.Add([]byte("test input"))
f.Fuzz(func(t *testing.T, data []byte) {
parser := NewParser(data)
// Should not panic
_, err := parser.Parse()
if err != nil {
t.Skip() // Expected error, not a crash
}
})
}Run with:
``bash
go test -fuzz=FuzzParser
Prevention Strategies
1. Constructor Pattern
Always use constructors for structs with pointers:
```go type Server struct { config *Config }
func NewServer(cfg *Config) (*Server, error) { if cfg == nil { return nil, errors.New("config cannot be nil") } return &Server{config: cfg}, nil } ```
2. nil-safe Methods
Design methods to handle nil receivers gracefully:
func (s *Server) Config() *Config {
if s == nil {
return nil
}
return s.config
}3. Use Static Analysis
```bash # nilaway from Uber go install go.uber.org/nilaway/cmd/nilaway@latest nilaway ./...
# staticcheck go install honnef.co/go/tools/cmd/staticcheck@latest staticcheck ./... ```