Commit a9e2479a authored by Ian Lance Taylor's avatar Ian Lance Taylor

bytes: set cap of slices returned by Split and Fields and friends

This avoids the problem in which appending to a slice returned by
Split can affect subsequent slices.

Fixes #21149.

Change-Id: Ie3df2b9ceeb9605d4625f47d49073c5f348cf0a1
Reviewed-on: https://go-review.googlesource.com/74510Reviewed-by: default avatarJelte Fennema <github-tech@jeltef.nl>
Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
parent 3043c355
...@@ -39,7 +39,7 @@ func explode(s []byte, n int) [][]byte { ...@@ -39,7 +39,7 @@ func explode(s []byte, n int) [][]byte {
break break
} }
_, size = utf8.DecodeRune(s) _, size = utf8.DecodeRune(s)
a[na] = s[0:size] a[na] = s[0:size:size]
s = s[size:] s = s[size:]
na++ na++
} }
...@@ -219,7 +219,7 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte { ...@@ -219,7 +219,7 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
if m < 0 { if m < 0 {
break break
} }
a[i] = s[:m+sepSave] a[i] = s[: m+sepSave : m+sepSave]
s = s[m+len(sep):] s = s[m+len(sep):]
i++ i++
} }
...@@ -302,7 +302,7 @@ func Fields(s []byte) [][]byte { ...@@ -302,7 +302,7 @@ func Fields(s []byte) [][]byte {
i++ i++
continue continue
} }
a[na] = s[fieldStart:i] a[na] = s[fieldStart:i:i]
na++ na++
i++ i++
// Skip spaces in between fields. // Skip spaces in between fields.
...@@ -312,7 +312,7 @@ func Fields(s []byte) [][]byte { ...@@ -312,7 +312,7 @@ func Fields(s []byte) [][]byte {
fieldStart = i fieldStart = i
} }
if fieldStart < len(s) { // Last field might end at EOF. if fieldStart < len(s) { // Last field might end at EOF.
a[na] = s[fieldStart:] a[na] = s[fieldStart:len(s):len(s)]
} }
return a return a
} }
...@@ -363,7 +363,7 @@ func FieldsFunc(s []byte, f func(rune) bool) [][]byte { ...@@ -363,7 +363,7 @@ func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
// Create subslices from recorded field indices. // Create subslices from recorded field indices.
a := make([][]byte, len(spans)) a := make([][]byte, len(spans))
for i, span := range spans { for i, span := range spans {
a[i] = s[span.start:span.end] a[i] = s[span.start:span.end:span.end]
} }
return a return a
......
...@@ -736,6 +736,13 @@ var splittests = []SplitTest{ ...@@ -736,6 +736,13 @@ var splittests = []SplitTest{
func TestSplit(t *testing.T) { func TestSplit(t *testing.T) {
for _, tt := range splittests { for _, tt := range splittests {
a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n) a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n)
// Appending to the results should not change future results.
var x []byte
for _, v := range a {
x = append(v, 'z')
}
result := sliceOfString(a) result := sliceOfString(a)
if !eq(result, tt.a) { if !eq(result, tt.a) {
t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
...@@ -744,6 +751,11 @@ func TestSplit(t *testing.T) { ...@@ -744,6 +751,11 @@ func TestSplit(t *testing.T) {
if tt.n == 0 { if tt.n == 0 {
continue continue
} }
if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
t.Errorf("last appended result was %s; want %s", x, want)
}
s := Join(a, []byte(tt.sep)) s := Join(a, []byte(tt.sep))
if string(s) != tt.s { if string(s) != tt.s {
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
...@@ -782,11 +794,23 @@ var splitaftertests = []SplitTest{ ...@@ -782,11 +794,23 @@ var splitaftertests = []SplitTest{
func TestSplitAfter(t *testing.T) { func TestSplitAfter(t *testing.T) {
for _, tt := range splitaftertests { for _, tt := range splitaftertests {
a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n) a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n)
// Appending to the results should not change future results.
var x []byte
for _, v := range a {
x = append(v, 'z')
}
result := sliceOfString(a) result := sliceOfString(a)
if !eq(result, tt.a) { if !eq(result, tt.a) {
t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a)
continue continue
} }
if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
t.Errorf("last appended result was %s; want %s", x, want)
}
s := Join(a, nil) s := Join(a, nil)
if string(s) != tt.s { if string(s) != tt.s {
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
...@@ -821,12 +845,29 @@ var fieldstests = []FieldsTest{ ...@@ -821,12 +845,29 @@ var fieldstests = []FieldsTest{
func TestFields(t *testing.T) { func TestFields(t *testing.T) {
for _, tt := range fieldstests { for _, tt := range fieldstests {
a := Fields([]byte(tt.s)) b := []byte(tt.s)
a := Fields(b)
// Appending to the results should not change future results.
var x []byte
for _, v := range a {
x = append(v, 'z')
}
result := sliceOfString(a) result := sliceOfString(a)
if !eq(result, tt.a) { if !eq(result, tt.a) {
t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a) t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
continue continue
} }
if string(b) != tt.s {
t.Errorf("slice changed to %s; want %s", string(b), tt.s)
}
if len(tt.a) > 0 {
if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
t.Errorf("last appended result was %s; want %s", x, want)
}
}
} }
} }
...@@ -847,11 +888,28 @@ func TestFieldsFunc(t *testing.T) { ...@@ -847,11 +888,28 @@ func TestFieldsFunc(t *testing.T) {
{"aXXbXXXcX", []string{"a", "b", "c"}}, {"aXXbXXXcX", []string{"a", "b", "c"}},
} }
for _, tt := range fieldsFuncTests { for _, tt := range fieldsFuncTests {
a := FieldsFunc([]byte(tt.s), pred) b := []byte(tt.s)
a := FieldsFunc(b, pred)
// Appending to the results should not change future results.
var x []byte
for _, v := range a {
x = append(v, 'z')
}
result := sliceOfString(a) result := sliceOfString(a)
if !eq(result, tt.a) { if !eq(result, tt.a) {
t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a) t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
} }
if string(b) != tt.s {
t.Errorf("slice changed to %s; want %s", b, tt.s)
}
if len(tt.a) > 0 {
if want := tt.a[len(tt.a)-1] + "z"; string(x) != want {
t.Errorf("last appended result was %s; want %s", x, want)
}
}
} }
} }
......
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