Skip to content

Instantly share code, notes, and snippets.

@joeduffy
Created July 17, 2015 22:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joeduffy/a820e31c14014cd7e057 to your computer and use it in GitHub Desktop.
Save joeduffy/a820e31c14014cd7e057 to your computer and use it in GitHub Desktop.
Breaking Go memory safety by violating concurrency safety.
// tear.go
// A simple demonstration of breaking Go memory safety by violating concurrency
// safety. We alias a shared slice variable -- which is a multi-word variable --
// and then reads/write that shared variable in parallel between Goroutines.
// If "torn slice: ..." is printed, something VeryBad(tm) has occurred...
package main
import (
"fmt"
"runtime"
)
func main() {
// Make sure we've got some parallelism.
runtime.GOMAXPROCS(32)
// Stamp out some blueprint slices we'll cycle through.
length := 1
swaps := make([][]int, 10)
for i := 0; i < len(swaps); i++ {
swaps[i] = make([]int, length)
for j := 0; j < length; j++ {
swaps[i][j] = j
}
length *= 2
}
// Kick off some goroutines that just continuosly read the shared slice.
shared := swaps[0] // A slice variable shared between all goroutines.
for i := 0; i < 16; i++ {
go func() {
for {
local := shared // Make a local copy (logically one read).
last := len(local) - 1
if local[last] != last {
// All of the arrays should have their 'len-1'th equal to
// 'len-1' (per 'swaps' above). If not, something went awry!
fmt.Printf("torn slice: %v/0x%x != %v/0x%x\n",
local[last], local[last], last, last)
}
}
}()
}
// Finally, continuously swap in our differently-sized slices into the
// shared variable.
for {
for _, swap := range swaps {
shared = swap
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment