1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:04:44 -07:00

math/big: Rat.SetString to report error if input is not consumed entirely

Also, document behavior explicitly for all SetString implementations.

Fixes #17001.

Change-Id: Iccc882b4bc7f8b61b6092f330e405c146a80dc98
Reviewed-on: https://go-review.googlesource.com/30472
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Robert Griesemer 2016-10-05 15:01:15 -07:00
parent 4103fedf19
commit 95a6572b2b
4 changed files with 23 additions and 10 deletions

View File

@ -14,7 +14,9 @@ import (
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s must be a floating-point number of the same format as accepted
// by Parse, with base argument 0.
// by Parse, with base argument 0. The entire string (not just a prefix) must
// be valid for success. If the operation failed, the value of z is undefined
// but the returned value is nil.
func (z *Float) SetString(s string) (*Float, bool) {
if f, _, err := z.Parse(s, 0); err == nil {
return f, true
@ -212,6 +214,7 @@ func (z *Float) pow5(n uint64) *Float {
//
// It sets z to the (possibly rounded) value of the corresponding floating-
// point value, and returns z, the actual base b, and an error err, if any.
// The entire string (not just a prefix) must be consumed for success.
// If z's precision is 0, it is changed to 64 before rounding takes effect.
// The number must be of the form:
//

View File

@ -361,7 +361,8 @@ func (x *Int) Uint64() uint64 {
}
// SetString sets z to the value of s, interpreted in the given base,
// and returns z and a boolean indicating success. If SetString fails,
// and returns z and a boolean indicating success. The entire string
// (not just a prefix) must be valid for success. If SetString fails,
// the value of z is undefined but the returned value is nil.
//
// The base argument must be 0 or a value between 2 and MaxBase. If the base
@ -371,12 +372,11 @@ func (x *Int) Uint64() uint64 {
//
func (z *Int) SetString(s string, base int) (*Int, bool) {
r := strings.NewReader(s)
_, _, err := z.scan(r, base)
if err != nil {
if _, _, err := z.scan(r, base); err != nil {
return nil, false
}
_, err = r.ReadByte()
if err != io.EOF {
// entire string must have been consumed
if _, err := r.ReadByte(); err != io.EOF {
return nil, false
}
return z, true // err == io.EOF => scan consumed all of s

View File

@ -36,8 +36,9 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s can be given as a fraction "a/b" or as a floating-point number
// optionally followed by an exponent. If the operation failed, the value of
// z is undefined but the returned value is nil.
// optionally followed by an exponent. The entire string (not just a prefix)
// must be valid for success. If the operation failed, the value of z is un-
// defined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 {
return nil, false
@ -49,9 +50,13 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if _, ok := z.a.SetString(s[:sep], 0); !ok {
return nil, false
}
s = s[sep+1:]
r := strings.NewReader(s[sep+1:])
var err error
if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
if z.b.abs, _, _, err = z.b.abs.scan(r, 0, false); err != nil {
return nil, false
}
// entire string must have been consumed
if _, err = r.ReadByte(); err != io.EOF {
return nil, false
}
if len(z.b.abs) == 0 {

View File

@ -50,6 +50,10 @@ var setStringTests = []StringTest{
{"204211327800791583.81095", "4084226556015831676219/20000", true},
{"0e9999999999", "0", true}, // issue #16176
{in: "1/0"},
{in: "4/3/2"}, // issue 17001
{in: "4/3/"},
{in: "4/3."},
{in: "4/"},
}
// These are not supported by fmt.Fscanf.
@ -59,6 +63,7 @@ var setStringTests2 = []StringTest{
{"-010.", "-10", true},
{"0x10/0x20", "1/2", true},
{"0b1000/3", "8/3", true},
{in: "4/3x"},
// TODO(gri) add more tests
}