mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
strings, bytes: panic if Repeat overflows or if given a negative count
Panic if Repeat is given a negative count or if the value of (len(*) * count) is detected to overflow. We panic because we cannot change the signature of Repeat to return an error. Fixes #16237 Change-Id: I9f5ba031a5b8533db0582d7a672ffb715143f3fb Reviewed-on: https://go-review.googlesource.com/29954 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
d166a369a8
commit
7b40b0c3a3
|
@ -365,7 +365,20 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat returns a new byte slice consisting of count copies of b.
|
// Repeat returns a new byte slice consisting of count copies of b.
|
||||||
|
//
|
||||||
|
// It panics if count is negative or if
|
||||||
|
// the result of (len(b) * count) overflows.
|
||||||
func Repeat(b []byte, count int) []byte {
|
func Repeat(b []byte, count int) []byte {
|
||||||
|
// Since we cannot return an error on overflow,
|
||||||
|
// we should panic if the repeat will generate
|
||||||
|
// an overflow.
|
||||||
|
// See Issue golang.org/issue/16237.
|
||||||
|
if count < 0 {
|
||||||
|
panic("bytes: negative Repeat count")
|
||||||
|
} else if count > 0 && len(b)*count/count != len(b) {
|
||||||
|
panic("bytes: Repeat count causes overflow")
|
||||||
|
}
|
||||||
|
|
||||||
nb := make([]byte, len(b)*count)
|
nb := make([]byte, len(b)*count)
|
||||||
bp := copy(nb, b)
|
bp := copy(nb, b)
|
||||||
for bp < len(nb) {
|
for bp < len(nb) {
|
||||||
|
|
|
@ -903,6 +903,54 @@ func TestRepeat(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func repeat(b []byte, count int) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
switch v := r.(type) {
|
||||||
|
case error:
|
||||||
|
err = v
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("%s", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
Repeat(b, count)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// See Issue golang.org/issue/16237
|
||||||
|
func TestRepeatCatchesOverflow(t *testing.T) {
|
||||||
|
tests := [...]struct {
|
||||||
|
s string
|
||||||
|
count int
|
||||||
|
errStr string
|
||||||
|
}{
|
||||||
|
0: {"--", -2147483647, "negative"},
|
||||||
|
1: {"", int(^uint(0) >> 1), ""},
|
||||||
|
2: {"-", 10, ""},
|
||||||
|
3: {"gopher", 0, ""},
|
||||||
|
4: {"-", -1, "negative"},
|
||||||
|
5: {"--", -102, "negative"},
|
||||||
|
6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
err := repeat([]byte(tt.s), tt.count)
|
||||||
|
if tt.errStr == "" {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d panicked %v", i, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil || !strings.Contains(err.Error(), tt.errStr) {
|
||||||
|
t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runesEqual(a, b []rune) bool {
|
func runesEqual(a, b []rune) bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -418,7 +418,20 @@ func Map(mapping func(rune) rune, s string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat returns a new string consisting of count copies of the string s.
|
// Repeat returns a new string consisting of count copies of the string s.
|
||||||
|
//
|
||||||
|
// It panics if count is negative or if
|
||||||
|
// the result of (len(s) * count) overflows.
|
||||||
func Repeat(s string, count int) string {
|
func Repeat(s string, count int) string {
|
||||||
|
// Since we cannot return an error on overflow,
|
||||||
|
// we should panic if the repeat will generate
|
||||||
|
// an overflow.
|
||||||
|
// See Issue golang.org/issue/16237
|
||||||
|
if count < 0 {
|
||||||
|
panic("strings: negative Repeat count")
|
||||||
|
} else if count > 0 && len(s)*count/count != len(s) {
|
||||||
|
panic("strings: Repeat count causes overflow")
|
||||||
|
}
|
||||||
|
|
||||||
b := make([]byte, len(s)*count)
|
b := make([]byte, len(s)*count)
|
||||||
bp := copy(b, s)
|
bp := copy(b, s)
|
||||||
for bp < len(b) {
|
for bp < len(b) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ package strings_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -892,6 +893,54 @@ func TestRepeat(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func repeat(s string, count int) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
switch v := r.(type) {
|
||||||
|
case error:
|
||||||
|
err = v
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("%s", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
Repeat(s, count)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// See Issue golang.org/issue/16237
|
||||||
|
func TestRepeatCatchesOverflow(t *testing.T) {
|
||||||
|
tests := [...]struct {
|
||||||
|
s string
|
||||||
|
count int
|
||||||
|
errStr string
|
||||||
|
}{
|
||||||
|
0: {"--", -2147483647, "negative"},
|
||||||
|
1: {"", int(^uint(0) >> 1), ""},
|
||||||
|
2: {"-", 10, ""},
|
||||||
|
3: {"gopher", 0, ""},
|
||||||
|
4: {"-", -1, "negative"},
|
||||||
|
5: {"--", -102, "negative"},
|
||||||
|
6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
err := repeat(tt.s, tt.count)
|
||||||
|
if tt.errStr == "" {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("#%d panicked %v", i, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil || !Contains(err.Error(), tt.errStr) {
|
||||||
|
t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runesEqual(a, b []rune) bool {
|
func runesEqual(a, b []rune) bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
|
|
Loading…
Reference in a new issue