]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: fix appendCompact escaping
authorAlexander Yastrebov <yastrebov.alex@gmail.com>
Thu, 5 Oct 2023 21:55:06 +0000 (21:55 +0000)
committerMichael Pratt <mpratt@google.com>
Fri, 6 Oct 2023 20:19:31 +0000 (20:19 +0000)
CL 469555 changed Compact to use append instead of bytes.Buffer.

appendCompact iterates over input src slice and performs escaping
of certain characters.
To optimize copying it does not copy characters one by one
but keeps track of the start offset of the data to copy when
it reaches next character to escape or the end of the input.

This start offset may become greater than input character offset
so copying of preceding data should check this condition.

CL 469555 removed boundary checks for copying data preceding
escaped characters and this change restores them.

Fixes https://github.com/golang/go/issues/63379

Change-Id: I5b7856239f256c67faf58834705675c0aea08cc2
GitHub-Last-Rev: 661576fb54951a05a8399beb3f9ac2a2f9a340b4
GitHub-Pull-Request: golang/go#63400
Reviewed-on: https://go-review.googlesource.com/c/go/+/533275
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/encoding/json/encode_test.go
src/encoding/json/indent.go

index 9c370280370b9ba9fe8efed3092b8a5b1de2956c..53259f4a9b78d77aeeaeed01742fc48ab2167bbc 100644 (file)
@@ -1193,3 +1193,29 @@ func TestMarshalerError(t *testing.T) {
                })
        }
 }
+
+type marshaledValue string
+
+func (v marshaledValue) MarshalJSON() ([]byte, error) {
+       return []byte(v), nil
+}
+
+func TestIssue63379(t *testing.T) {
+       for _, v := range []string{
+               "[]<",
+               "[]>",
+               "[]&",
+               "[]\u2028",
+               "[]\u2029",
+               "{}<",
+               "{}>",
+               "{}&",
+               "{}\u2028",
+               "{}\u2029",
+       } {
+               _, err := Marshal(marshaledValue(v))
+               if err == nil {
+                       t.Errorf("expected error for %q", v)
+               }
+       }
+}
index 26bb5d2e470023d8c7c0eaa72d5faab8a846f48f..01bfdf65e7d5e1834f392ccc89ac50a02ffd8874 100644 (file)
@@ -53,29 +53,37 @@ func appendCompact(dst, src []byte, escape bool) ([]byte, error) {
        start := 0
        for i, c := range src {
                if escape && (c == '<' || c == '>' || c == '&') {
-                       dst = append(dst, src[start:i]...)
+                       if start < i {
+                               dst = append(dst, src[start:i]...)
+                       }
                        dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF])
                        start = i + 1
                }
                // Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
                if escape && c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
-                       dst = append(dst, src[start:i]...)
+                       if start < i {
+                               dst = append(dst, src[start:i]...)
+                       }
                        dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF])
-                       start = i + len("\u2029")
+                       start = i + 3
                }
                v := scan.step(scan, c)
                if v >= scanSkipSpace {
                        if v == scanError {
                                break
                        }
-                       dst = append(dst, src[start:i]...)
+                       if start < i {
+                               dst = append(dst, src[start:i]...)
+                       }
                        start = i + 1
                }
        }
        if scan.eof() == scanError {
                return dst[:origLen], scan.err
        }
-       dst = append(dst, src[start:]...)
+       if start < len(src) {
+               dst = append(dst, src[start:]...)
+       }
        return dst, nil
 }