Skip to content

Instantly share code, notes, and snippets.

@mgood
Created January 31, 2019 19:06
Show Gist options
  • Save mgood/2f92cbfa67bfb15fef5b59617a466d30 to your computer and use it in GitHub Desktop.
Save mgood/2f92cbfa67bfb15fef5b59617a466d30 to your computer and use it in GitHub Desktop.
Go reflect.MakeFunc crash reproduction
package main
import (
"context"
"log"
"os"
"os/signal"
"reflect"
"strings"
"syscall"
"time"
)
func NewFlag(getFuncVar interface{}) interface{} {
fv := reflect.ValueOf(getFuncVar)
ft := fv.Type().Elem()
fv.Elem().Set(reflect.MakeFunc(ft, func(args []reflect.Value) []reflect.Value {
value := (*A)(nil)
return []reflect.Value{reflect.ValueOf(value)}
}))
return nil
}
var (
SomeFlagOverride func(context.Context) *A
_ = NewFlag(&SomeFlagOverride)
)
func ptrString(x string) *string { return &x }
func main() {
c := context.Background()
GetSomeFlag := func(c context.Context) *string {
override := SomeFlagOverride(c)
if override != nil {
return ptrString(override.A)
}
s := GetFlags().SomeFlag.A
return ptrString(s)
}
log.Printf("starting...")
time.Sleep(1 * time.Second)
for i := 0; i < 10; i++ {
go func() {
for {
GetSomeFlag(c)
}
}()
}
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)
<-sigs
}
type Flags struct {
// This is the only flag we're interested in for the test
SomeFlag *A
// The rest are the fields are junk to excercise the GC
A *D
B *D
C *D
D *D
E *D
K1 [64]byte
K2 [64]byte
K3 [64]byte
K4 [64]byte
}
func GetFlags() Flags {
return Flags{
SomeFlag: &A{
A: "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ",
},
A: NewD(),
B: NewD(),
C: NewD(),
D: NewD(),
E: NewD(),
K1: [64]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
},
K2: [64]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
},
K3: [64]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
},
K4: [64]byte{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
},
}
}
type A struct {
A string
B string
C string
D string
E string
}
func NewA() *A {
return &A{
A: strings.Repeat("a", 20),
B: strings.Repeat("b", 20),
C: strings.Repeat("c", 20),
D: strings.Repeat("d", 20),
E: strings.Repeat("e", 20),
}
}
type B struct {
A *A
B *A
C *A
D *A
E *A
}
func NewB() *B {
return &B{
A: NewA(),
B: NewA(),
C: NewA(),
D: NewA(),
E: NewA(),
}
}
type C struct {
A *B
B *B
C *B
D *B
E *B
}
func NewC() *C {
return &C{
A: NewB(),
B: NewB(),
C: NewB(),
D: NewB(),
E: NewB(),
}
}
type D struct {
A *C
B *C
C *C
D *C
E *C
}
func NewD() *D {
return &D{
A: NewC(),
B: NewC(),
C: NewC(),
D: NewC(),
E: NewC(),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment