What version of protobuf and what language are you using? Version: master, Go
What did you do?
With the parseNumber function:
func main() {
n, ok := parseNumber([]byte("1234,anything can come after the comma"))
if ok {
panic(fmt.Sprintf("should not be ok, %d", n))
}
}
panics with should not be ok, 4
, indicating that it parsed "1234,anything can come after the comma"
into the integer 1234
, even though this should really throw an error.
What did you expect to see?
ok == false
What did you see instead?
ok == true
Anything else we should know about your project / environment? No
Comment From: dsnet
The parseNumber
function is internal to the package and only parses a JSON number out of the front of the input. Is this somehow resulting in a bug in the observable API for protojson
?
Comment From: MarTango
Yes, this propagates up to protojson level. For example if I have a protobuf
message HasInt {
int64 value = 1;
}
I can do
v := &HasInt{}
protojson.Unmarshal([]byte(`{"value": "1,lol"}`, v)
which will succeed, and unmarshal such that v.Value == 1
Comment From: dsnet
Thanks, I recommend next time filing the buggy observed behavior rather than pointing at a particular internal function. The behavior of parseNumber
is correct. I suspect the problem is actually parseNumberParts
, which should probably reject trailing data since it's only called from the context of a standalone token.
Comment From: kitami1976
The same behavior is observed if the string contains spaces:
v := &HasInt{}
protojson.Unmarshal([]byte(`{"value": "1 2"}`, v)
I think the problem might be in the unmarshalInt(), unmarshalUint() and unmarshalFloat() methods in protobuf/encoding/protojson/decode.go
. They all create a new decoder to decode the string value in case tok.Kind() == json.String
, but dec.Read()
doesn't necessarily read the entire string.
One possible fix is to add a second invocation to Read() to detect EOF: ````go tok1, err := dec.Read() if err != nil || tok1.Kind() != json.EOF { return protoreflect.Value{}, false }