Commit 2eb8f1da authored by Levin Zimmermann's avatar Levin Zimmermann

go/neo/proto/msgpack: Fix 'types.Struct' decoding

In NEO/go protocol, we describe some parameters that can
be send via NEO packages with structures. On the wire all of
these structures are encoded as msgpack arrays [1]. Msgpack
arrays can have 1 or more bytes as a header [2]. Therefore
it's better to use "ReadArrayHeaderBytes" than using

  >>> data = data[1:]

which fails in case we have array with 3 or 5 header bytes.

[1] One could also declare a protocol where these parameters aren't
    send as msgpack arrays but as msgpack maps. See here for the
    msgpack map specification:

    https://github.com/msgpack/msgpack/blob/9aa092d6ca81/spec.md?plain=1#L338

[2] https://github.com/msgpack/msgpack/blob/9aa092d6ca81/spec.md?plain=1#L315
parent a551361b
...@@ -635,6 +635,10 @@ type OverflowCheck struct { ...@@ -635,6 +635,10 @@ type OverflowCheck struct {
// stack operated by {Push,Pop}Checked // stack operated by {Push,Pop}Checked
checkedStk []bool checkedStk []bool
// whether any 'goto overflow' has been emitted for
// current decoder
gotoEmitted bool
} }
// push/pop checked state // push/pop checked state
...@@ -819,6 +823,8 @@ func (d *decoderCommon) overflowCheck() { ...@@ -819,6 +823,8 @@ func (d *decoderCommon) overflowCheck() {
lendata = "uint64(" + lendata + ")" lendata = "uint64(" + lendata + ")"
} }
d.bufDone.emit("if %s < %v { goto overflow }", lendata, &d.overflow.checkSize) d.bufDone.emit("if %s < %v { goto overflow }", lendata, &d.overflow.checkSize)
// Flag that we already committed a 'goto overflow' statement in current decoder
d.overflow.gotoEmitted = true
// if size for overflow check was only numeric - just // if size for overflow check was only numeric - just
// accumulate it at generation time // accumulate it at generation time
...@@ -901,7 +907,7 @@ func (d *decoderCommon) generatedCode() string { ...@@ -901,7 +907,7 @@ func (d *decoderCommon) generatedCode() string {
// `goto overflow` is not used only for empty structs // `goto overflow` is not used only for empty structs
// NOTE for >0 check actual X in StdSizes{X} does not particularly matter // NOTE for >0 check actual X in StdSizes{X} does not particularly matter
if (&types.StdSizes{8, 8}).Sizeof(d.typ) > 0 || d.enc != 'N' { if ((&types.StdSizes{8, 8}).Sizeof(d.typ) > 0 || d.enc != 'N') && d.overflow.gotoEmitted {
code.emit("\noverflow:") code.emit("\noverflow:")
code.emit("return 0, ErrDecodeOverflow") code.emit("return 0, ErrDecodeOverflow")
} }
...@@ -1735,8 +1741,22 @@ func (d *decoderM) genStructHead(path string, typ *types.Struct, userType types. ...@@ -1735,8 +1741,22 @@ func (d *decoderM) genStructHead(path string, typ *types.Struct, userType types.
d.emit("return 0, &mstructDecodeError{%q, op, opOk}", d.pathName(path)) d.emit("return 0, &mstructDecodeError{%q, op, opOk}", d.pathName(path))
d.emit("}") d.emit("}")
d.n += 1 d.resetPos()
d.overflow.Add(1)
// we are going to go into msgp - flush previously queued
// overflow checks; put place for next overflow check after
// msgp is done.
d.overflowCheck()
defer d.overflowCheck()
d.emit("{")
d.emit("l, tail, err := msgp.ReadArrayHeaderBytes(data)")
d.emit("if err != nil {")
d.emit(fmt.Sprintf("return 0, mdecodeErr(%q, err)", d.pathName(path)))
d.emit("}")
d.emit("data = tail")
d.emit("%v += uint64(l)", d.var_("nread"))
d.emit("}")
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment