Torn slices in Go that defy intuition

<2024-11-03 Sun>

There is a very strange Go slice that identifies with nil and yet has a non-zero length. This slice made an appearance in a prod system and really made everybody's day.

var xs []int

if len(xs) == 1 && xs == nil {
      panic("This is impossible, right?")
}

Reference ticket.

What is happening under the hood?

A Go slice is a struct-like structure, somewhat like this:

type s struct {
      array *ptr
      offset int
      length int
}

Now, xs == nil should not have been possible for a struct-like structure but is so common it must have been included for convenience. What it actually desugars to is xs.array == nil.

When memory is shared across goroutines in a data race, one goroutine can modify the array pointer and make it nil. At the same time the length data remains non-zero to the confusion of another goroutine.

Clojure is having an I-told-you-so moment. Concurrency and mutable state do not mix well together.


index :: about