-
Notifications
You must be signed in to change notification settings - Fork 30
generalListDecoder panics when iterator timeout on decoding message #19
Description
When decoding a message, the Decoder.Decode method is called. (the following code snippet)
Line 24 (L24) tries to decode the message, and it will check the error of iter on decoding finished (L25). However, the L24 may panic (instead of return normally). When the L24 panics, the whole method will panic, not returning the expected error.
Lines 16 to 29 in 9b5a675
| func (decoder *Decoder) Decode(val interface{}) error { | |
| cfg := decoder.cfg | |
| valType := reflect.TypeOf(val) | |
| valDecoder := cfg.getGenDecoder(valType) | |
| if valDecoder == nil { | |
| valDecoder = cfg.decoderOf(valType) | |
| cfg.addGenDecoder(valType, valDecoder) | |
| } | |
| valDecoder.Decode(val, decoder.iter) | |
| if decoder.iter.Error() != nil { | |
| return decoder.iter.Error() | |
| } | |
| return nil | |
| } |
Following is the method where panic may occur.
The underlying Reader of iter may read from a TCP connection (L13). But TCP connection can run timeout, then the underlying Reader will get an error. When such error occurs, the iter will return zero values and set an error. (thus elemType == TypeStop && length == 0 && iter.Error() != nil) When trying to get the generalReaderOf(TypeStop) (L14), this method will panic (See the code snippet, go/general/decode.go#L31).
Lines 8 to 20 in 9b5a675
| func (decoder *generalListDecoder) Decode(val interface{}, iter spi.Iterator) { | |
| *val.(*List) = readList(iter).(List) | |
| } | |
| func readList(iter spi.Iterator) interface{} { | |
| elemType, length := iter.ReadListHeader() | |
| generalReader := generalReaderOf(elemType) | |
| var generalList List | |
| for i := 0; i < length; i++ { | |
| generalList = append(generalList, generalReader(iter)) | |
| } | |
| return generalList | |
| } |
Lines 8 to 33 in 9b5a675
| func generalReaderOf(ttype protocol.TType) func(iter spi.Iterator) interface{} { | |
| switch ttype { | |
| case protocol.TypeBool: | |
| return readBool | |
| case protocol.TypeI08: | |
| return readInt8 | |
| case protocol.TypeI16: | |
| return readInt16 | |
| case protocol.TypeI32: | |
| return readInt32 | |
| case protocol.TypeI64: | |
| return readInt64 | |
| case protocol.TypeString: | |
| return readString | |
| case protocol.TypeDouble: | |
| return readFloat64 | |
| case protocol.TypeList: | |
| return readList | |
| case protocol.TypeMap: | |
| return readMap | |
| case protocol.TypeStruct: | |
| return readStruct | |
| default: | |
| panic("unsupported type") | |
| } | |
| } |