Skip to content

Instantly share code, notes, and snippets.

@joeduffy
Created July 18, 2015 15:40
Show Gist options
  • Save joeduffy/0cf84adbe6ada42a6fc6 to your computer and use it in GitHub Desktop.
Save joeduffy/0cf84adbe6ada42a6fc6 to your computer and use it in GitHub Desktop.
Breaking Go memory safety by violating concurrency safety (#2: interfaces).
// teariface.go
// A simple demonstration of breaking Go memory safety by violating concurrency
// safety. We alias an interface variable which is of course multiple words;
// the net result is the itable pointer and target object pointer end up
// mismatched, triggering undefined behavior (wrong results, AVs, etc).
package main
import (
"fmt"
"runtime"
)
type I interface {
F() string
M() string
}
type A struct {
nm string
}
func (a *A) F() string { return a.nm }
func (a *A) M() string { return "A" }
func MakeA() *A { return &A{nm: "A"} }
type B struct {
nm string
}
func (b *B) F() string { return b.nm }
func (b *B) M() string { return "B" }
func MakeB() *B { return &B{nm: "B"} }
type C struct {
// No field!
}
func (c *C) F() string { return "C" }
func (c *C) M() string { return "C" }
func MakeC() *C { return &C{} }
func main() {
// Make sure we've got some parallelism.
runtime.GOMAXPROCS(32)
a := MakeA()
b := MakeB()
c := MakeC()
var shared I
shared = a // Initially an A.
// Kick off some goroutines that just continuosly read the shared obj.
for i := 0; i < 16; i++ {
go func() {
for {
local := shared // Make a local copy (logically one read).
if local.F() != local.M() {
// All Fs should == Ms.
fmt.Printf("torn face: '%v' != '%v'\n",
local.F(), local.M())
}
}
}()
}
// Finally, continuously swap in our A, B, and C typed pointers.
for {
shared = b
shared = c
shared = a
shared = c
shared = b
shared = a
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment