Change:
In Go you cannot take the address of a because the map implementation hides that from you. Our conversion library assumes that any reflected map value can have Addr() taken, which causes a panic when you try to do the following for PodInfo conversion: The conversion code tries to call Addr() on the reflect.Value (the map's value, ContainerStatus value object) which fails because it cannot have an address. I worked around it by registering a conversion function on *PodInfo and then manually converting the map.
Oh you mean the reflection code can't addr that? ok sounds like a bug. Non-reflection code can certainly do it:
That playground is taking the address of a value before it's in the struct. You can't take the address of m ----- Original Message -----
Right, because go does magical c++ style references there. But I thought the map copying code handled that case specially already?
I think I see what you're talking about. I'll make a test.
I repro'd. Will fix.
It was actually the source value that caused the trouble. Thanks for the report!
Sorry, should have been clearer. ----- Original Message -----
Note that this map violates our API conventions. It should be a list of named subobjects.
Yeah this field has always been problematic. It's still a bug regardless-- could have triggered copying other maps.

Discussion:
if err != nil { return err } <del> if !dv.CanAddr() { </del> <ins> if !dv.CanAddr() && !dv.CanSet() { </ins> return fmt.Errorf("can't write to dest") } sv, err := EnforcePtr(src)

return c.convert(sv, dv, s) } <ins> // callCustom calls 'custom' with sv & dv. custom must be a conversion function. func (c *Converter) callCustom(sv, dv, custom reflect.Value, scope *scope) error { if !sv.CanAddr() { sv2 := reflect.New(sv.Type()) sv2.Elem().Set(sv) sv = sv2 } else { sv = sv.Addr() } if !dv.CanAddr() { if !dv.CanSet() { return scope.error("can't addr or set dest.") } dvOrig := dv dv := reflect.New(dvOrig.Type()) defer func() { dvOrig.Set(dv) }() } else { dv = dv.Addr() } args := []reflect.Value{sv, dv, reflect.ValueOf(scope)} ret := custom.Call(args)[0].Interface() // This convolution is necessary because nil interfaces won't convert // to errors. if ret == nil { return nil } return ret.(error) } </ins> // convert recursively copies sv into dv, calling an appropriate conversion function if // one is registered. func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error {

if c.Debug != nil { c.Debug.Logf("Calling custom conversion of '%v' to '%v'", st, dt) } <del> args := []reflect.Value{sv.Addr(), dv.Addr(), reflect.ValueOf(scope)} ret := fv.Call(args)[0].Interface() // This convolution is necessary because nil interfaces won't convert // to errors. if ret == nil { return nil } return ret.(error) </del> <ins> return c.callCustom(sv, dv, fv, scope) </ins> } if !scope.flags.IsSet(AllowDifferentFieldTypeNames) && c.NameFunc(dt) != c.NameFunc(st) {

import ( "fmt" "reflect" <ins> "strconv" </ins> "testing" "github.com/google/gofuzz"

} } <ins> func TestConverter_MapElemAddr(t *testing.T) { type Foo struct { A map[int]int } type Bar struct { A map[string]string } c := NewConverter() c.Debug = t err := c.Register( func(in *int, out *string, s Scope) error { *out = fmt.Sprintf("%v", *in) return nil }, ) if err != nil { t.Fatalf("Unexpected error: %v", err) } err = c.Register( func(in *string, out *int, s Scope) error { if str, err := strconv.Atoi(*in); err != nil { return err } else { *out = str return nil } }, ) if err != nil { t.Fatalf("Unexpected error: %v", err) } f := fuzz.New().NilChance(0).NumElements(3, 3) first := Foo{} second := Bar{} f.Fuzz(&first) err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } third := Foo{} err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil) if e, a := first, third; !reflect.DeepEqual(e, a) { t.Errorf("Unexpected diff: %v", objDiff(e, a)) } } </ins> func TestConverter_tags(t *testing.T) { type Foo struct { A string `test:"foo"`

if err != nil { t.Fatalf("Unexpected error: %v", err) } <del> c.Convert(&Foo{}, &Bar{}, 0, nil) </del> <ins> err = c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } </ins> } func TestConverter_meta(t *testing.T) {