@@ -671,7 +671,7 @@ func (dec *Decoder) ignoreInterface(state *decodeState) {
671
671
}
672
672
673
673
// Index by Go types.
674
- var decOpMap = []decOp {
674
+ var decOpTable = [... ]decOp {
675
675
reflect .Bool : decBool ,
676
676
reflect .Int8 : decInt8 ,
677
677
reflect .Int16 : decInt16 ,
@@ -701,37 +701,43 @@ var decIgnoreOpMap = map[typeId]decOp{
701
701
702
702
// Return the decoding op for the base type under rt and
703
703
// the indirection count to reach it.
704
- func (dec * Decoder ) decOpFor (wireId typeId , rt reflect.Type , name string ) (decOp , int ) {
704
+ func (dec * Decoder ) decOpFor (wireId typeId , rt reflect.Type , name string , inProgress map [reflect. Type ] * decOp ) (* decOp , int ) {
705
705
ut := userType (rt )
706
+ // If this type is already in progress, it's a recursive type (e.g. map[string]*T).
707
+ // Return the pointer to the op we're already building.
708
+ if opPtr := inProgress [rt ]; opPtr != nil {
709
+ return opPtr , ut .indir
710
+ }
706
711
typ := ut .base
707
712
indir := ut .indir
708
713
var op decOp
709
714
k := typ .Kind ()
710
- if int (k ) < len (decOpMap ) {
711
- op = decOpMap [k ]
715
+ if int (k ) < len (decOpTable ) {
716
+ op = decOpTable [k ]
712
717
}
713
718
if op == nil {
719
+ inProgress [rt ] = & op
714
720
// Special cases
715
721
switch t := typ .(type ) {
716
722
case * reflect.ArrayType :
717
723
name = "element of " + name
718
724
elemId := dec .wireType [wireId ].ArrayT .Elem
719
- elemOp , elemIndir := dec .decOpFor (elemId , t .Elem (), name )
725
+ elemOp , elemIndir := dec .decOpFor (elemId , t .Elem (), name , inProgress )
720
726
ovfl := overflow (name )
721
727
op = func (i * decInstr , state * decodeState , p unsafe.Pointer ) {
722
- state .dec .decodeArray (t , state , uintptr (p ), elemOp , t .Elem ().Size (), t .Len (), i .indir , elemIndir , ovfl )
728
+ state .dec .decodeArray (t , state , uintptr (p ), * elemOp , t .Elem ().Size (), t .Len (), i .indir , elemIndir , ovfl )
723
729
}
724
730
725
731
case * reflect.MapType :
726
732
name = "element of " + name
727
733
keyId := dec .wireType [wireId ].MapT .Key
728
734
elemId := dec .wireType [wireId ].MapT .Elem
729
- keyOp , keyIndir := dec .decOpFor (keyId , t .Key (), name )
730
- elemOp , elemIndir := dec .decOpFor (elemId , t .Elem (), name )
735
+ keyOp , keyIndir := dec .decOpFor (keyId , t .Key (), name , inProgress )
736
+ elemOp , elemIndir := dec .decOpFor (elemId , t .Elem (), name , inProgress )
731
737
ovfl := overflow (name )
732
738
op = func (i * decInstr , state * decodeState , p unsafe.Pointer ) {
733
739
up := unsafe .Pointer (p )
734
- state .dec .decodeMap (t , state , uintptr (up ), keyOp , elemOp , i .indir , keyIndir , elemIndir , ovfl )
740
+ state .dec .decodeMap (t , state , uintptr (up ), * keyOp , * elemOp , i .indir , keyIndir , elemIndir , ovfl )
735
741
}
736
742
737
743
case * reflect.SliceType :
@@ -746,10 +752,10 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
746
752
} else {
747
753
elemId = dec .wireType [wireId ].SliceT .Elem
748
754
}
749
- elemOp , elemIndir := dec .decOpFor (elemId , t .Elem (), name )
755
+ elemOp , elemIndir := dec .decOpFor (elemId , t .Elem (), name , inProgress )
750
756
ovfl := overflow (name )
751
757
op = func (i * decInstr , state * decodeState , p unsafe.Pointer ) {
752
- state .dec .decodeSlice (t , state , uintptr (p ), elemOp , t .Elem ().Size (), i .indir , elemIndir , ovfl )
758
+ state .dec .decodeSlice (t , state , uintptr (p ), * elemOp , t .Elem ().Size (), i .indir , elemIndir , ovfl )
753
759
}
754
760
755
761
case * reflect.StructType :
@@ -774,7 +780,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
774
780
if op == nil {
775
781
errorf ("gob: decode can't handle type %s" , rt .String ())
776
782
}
777
- return op , indir
783
+ return & op , indir
778
784
}
779
785
780
786
// Return the decoding op for a field that has no destination.
@@ -838,11 +844,15 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
838
844
// Are these two gob Types compatible?
839
845
// Answers the question for basic types, arrays, and slices.
840
846
// Structs are considered ok; fields will be checked later.
841
- func (dec * Decoder ) compatibleType (fr reflect.Type , fw typeId ) bool {
847
+ func (dec * Decoder ) compatibleType (fr reflect.Type , fw typeId , inProgress map [reflect.Type ]typeId ) bool {
848
+ if rhs , ok := inProgress [fr ]; ok {
849
+ return rhs == fw
850
+ }
851
+ inProgress [fr ] = fw
842
852
fr = userType (fr ).base
843
853
switch t := fr .(type ) {
844
854
default :
845
- // map, chan, etc: cannot handle.
855
+ // chan, etc: cannot handle.
846
856
return false
847
857
case * reflect.BoolType :
848
858
return fw == tBool
@@ -864,14 +874,14 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
864
874
return false
865
875
}
866
876
array := wire .ArrayT
867
- return t .Len () == array .Len && dec .compatibleType (t .Elem (), array .Elem )
877
+ return t .Len () == array .Len && dec .compatibleType (t .Elem (), array .Elem , inProgress )
868
878
case * reflect.MapType :
869
879
wire , ok := dec .wireType [fw ]
870
880
if ! ok || wire .MapT == nil {
871
881
return false
872
882
}
873
883
MapType := wire .MapT
874
- return dec .compatibleType (t .Key (), MapType .Key ) && dec .compatibleType (t .Elem (), MapType .Elem )
884
+ return dec .compatibleType (t .Key (), MapType .Key , inProgress ) && dec .compatibleType (t .Elem (), MapType .Elem , inProgress )
875
885
case * reflect.SliceType :
876
886
// Is it an array of bytes?
877
887
if t .Elem ().Kind () == reflect .Uint8 {
@@ -885,7 +895,7 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
885
895
sw = dec .wireType [fw ].SliceT
886
896
}
887
897
elem := userType (t .Elem ()).base
888
- return sw != nil && dec .compatibleType (elem , sw .Elem )
898
+ return sw != nil && dec .compatibleType (elem , sw .Elem , inProgress )
889
899
case * reflect.StructType :
890
900
return true
891
901
}
@@ -906,12 +916,12 @@ func (dec *Decoder) compileSingle(remoteId typeId, rt reflect.Type) (engine *dec
906
916
engine = new (decEngine )
907
917
engine .instr = make ([]decInstr , 1 ) // one item
908
918
name := rt .String () // best we can do
909
- if ! dec .compatibleType (rt , remoteId ) {
919
+ if ! dec .compatibleType (rt , remoteId , make ( map [reflect. Type ] typeId ) ) {
910
920
return nil , os .ErrorString ("gob: wrong type received for local value " + name + ": " + dec .typeString (remoteId ))
911
921
}
912
- op , indir := dec .decOpFor (remoteId , rt , name )
922
+ op , indir := dec .decOpFor (remoteId , rt , name , make ( map [reflect. Type ] * decOp ) )
913
923
ovfl := os .ErrorString (`value for "` + name + `" out of range` )
914
- engine .instr [singletonField ] = decInstr {op , singletonField , indir , 0 , ovfl }
924
+ engine .instr [singletonField ] = decInstr {* op , singletonField , indir , 0 , ovfl }
915
925
engine .numInstr = 1
916
926
return
917
927
}
@@ -954,6 +964,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng
954
964
}
955
965
engine = new (decEngine )
956
966
engine .instr = make ([]decInstr , len (wireStruct .Field ))
967
+ seen := make (map [reflect.Type ]* decOp )
957
968
// Loop over the fields of the wire type.
958
969
for fieldnum := 0 ; fieldnum < len (wireStruct .Field ); fieldnum ++ {
959
970
wireField := wireStruct .Field [fieldnum ]
@@ -969,11 +980,11 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng
969
980
engine .instr [fieldnum ] = decInstr {op , fieldnum , 0 , 0 , ovfl }
970
981
continue
971
982
}
972
- if ! dec .compatibleType (localField .Type , wireField .Id ) {
983
+ if ! dec .compatibleType (localField .Type , wireField .Id , make ( map [reflect. Type ] typeId ) ) {
973
984
errorf ("gob: wrong type (%s) for received field %s.%s" , localField .Type , wireStruct .Name , wireField .Name )
974
985
}
975
- op , indir := dec .decOpFor (wireField .Id , localField .Type , localField .Name )
976
- engine .instr [fieldnum ] = decInstr {op , fieldnum , indir , uintptr (localField .Offset ), ovfl }
986
+ op , indir := dec .decOpFor (wireField .Id , localField .Type , localField .Name , seen )
987
+ engine .instr [fieldnum ] = decInstr {* op , fieldnum , indir , uintptr (localField .Offset ), ovfl }
977
988
engine .numInstr ++
978
989
}
979
990
return
@@ -1070,8 +1081,8 @@ func init() {
1070
1081
default :
1071
1082
panic ("gob: unknown size of int/uint" )
1072
1083
}
1073
- decOpMap [reflect .Int ] = iop
1074
- decOpMap [reflect .Uint ] = uop
1084
+ decOpTable [reflect .Int ] = iop
1085
+ decOpTable [reflect .Uint ] = uop
1075
1086
1076
1087
// Finally uintptr
1077
1088
switch reflect .Typeof (uintptr (0 )).Bits () {
@@ -1082,5 +1093,5 @@ func init() {
1082
1093
default :
1083
1094
panic ("gob: unknown size of uintptr" )
1084
1095
}
1085
- decOpMap [reflect .Uintptr ] = uop
1096
+ decOpTable [reflect .Uintptr ] = uop
1086
1097
}
0 commit comments