Skip to content

Instantly share code, notes, and snippets.

@joeduffy
Created July 17, 2015 22:24

Revisions

  1. joeduffy created this gist Jul 17, 2015.
    52 changes: 52 additions & 0 deletions tear.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,52 @@
    // 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
    }
    }
    }