]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/xml: accept chains of interfaces and pointers
authorRuss Cox <rsc@golang.org>
Thu, 17 Oct 2013 16:13:33 +0000 (12:13 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 17 Oct 2013 16:13:33 +0000 (12:13 -0400)
Fixes #6556.

R=golang-dev, iant, adg
CC=golang-dev
https://golang.org/cl/14747043

src/pkg/encoding/xml/marshal.go
src/pkg/encoding/xml/marshal_test.go

index e723a193cf7ebd8c043137a5e711ac9fb749fa28..d9522e0b39f718c0a24dfadfdd9a5ade616cd2f6 100644 (file)
@@ -354,18 +354,19 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
                return nil
        }
 
-       kind := val.Kind()
-       typ := val.Type()
-
-       // Drill into pointers/interfaces
-       if kind == reflect.Ptr || kind == reflect.Interface {
+       // Drill into interfaces and pointers.
+       // This can turn into an infinite loop given a cyclic chain,
+       // but it matches the Go 1 behavior.
+       for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
                if val.IsNil() {
                        return nil
                }
                val = val.Elem()
-               typ = val.Type()
        }
 
+       kind := val.Kind()
+       typ := val.Type()
+
        // Check for marshaler.
        if val.CanInterface() && typ.Implements(marshalerType) {
                return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
index 1444c9cc2f7bb743fa6a2d134cb0ab1b75f6d205..d34118a3d8b7f7cf9708387e4936eec3fa891dd5 100644 (file)
@@ -314,6 +314,10 @@ type MarshalerStruct struct {
        Foo MyMarshalerAttrTest `xml:",attr"`
 }
 
+func ifaceptr(x interface{}) interface{} {
+       return &x
+}
+
 var (
        nameAttr     = "Sarah"
        ageAttr      = uint(12)
@@ -356,6 +360,7 @@ var marshalTests = []struct {
        {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
        {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
        {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
+       {Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
 
        // Test time.
        {
@@ -1113,3 +1118,34 @@ func BenchmarkUnmarshal(b *testing.B) {
                Unmarshal(xml, &Feed{})
        }
 }
+
+// golang.org/issue/6556
+func TestStructPointerMarshal(t *testing.T) {
+       type A struct {
+               XMLName string `xml:"a"`
+               B       []interface{}
+       }
+       type C struct {
+               XMLName Name
+               Value   string `xml:"value"`
+       }
+
+       a := new(A)
+       a.B = append(a.B, &C{
+               XMLName: Name{Local: "c"},
+               Value:   "x",
+       })
+
+       b, err := Marshal(a)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if x := string(b); x != "<a><c><value>x</value></c></a>" {
+               t.Fatal(x)
+       }
+       var v A
+       err = Unmarshal(b, &v)
+       if err != nil {
+               t.Fatal(err)
+       }
+}