From d7b34d5f29324d77fad572676f0ea139556235e0 Mon Sep 17 00:00:00 2001 From: Martin Möhrmann Date: Sun, 30 Oct 2016 01:54:19 +0200 Subject: runtime: improve atoi implementation - Adds overflow checks - Adds parsing of negative integers - Adds boolean return value to signal parsing errors - Adds atoi32 for parsing of integers that fit in an int32 - Adds tests Handling of errors to provide error messages at the call sites is left to future CLs. Updates #17718 Change-Id: I3cacd0ab1230b9efc5404c68edae7304d39bcbc0 Reviewed-on: https://go-review.googlesource.com/32390 Reviewed-by: Ian Lance Taylor Reviewed-by: Brad Fitzpatrick --- src/runtime/string.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) (limited to 'src/runtime/string.go') diff --git a/src/runtime/string.go b/src/runtime/string.go index 07528236ee..822adaacf1 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -320,13 +320,66 @@ func hasprefix(s, t string) bool { return len(s) >= len(t) && s[:len(t)] == t } -func atoi(s string) int { - n := 0 - for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { - n = n*10 + int(s[0]) - '0' +const ( + maxUint = ^uint(0) + maxInt = int(maxUint >> 1) +) + +// atoi parses an int from a string s. +// The bool result reports whether s is a number +// representable by a value of type int. +func atoi(s string) (int, bool) { + if s == "" { + return 0, false + } + + neg := false + if s[0] == '-' { + neg = true s = s[1:] } - return n + + un := uint(0) + for i := 0; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + return 0, false + } + if un > maxUint/10 { + // overflow + return 0, false + } + un *= 10 + un1 := un + uint(c) - '0' + if un1 < un { + // overflow + return 0, false + } + un = un1 + } + + if !neg && un > uint(maxInt) { + return 0, false + } + if neg && un > uint(maxInt)+1 { + return 0, false + } + + n := int(un) + if neg { + n = -n + } + + return n, true +} + +// atoi32 is like atoi but for integers +// that fit into an int32. +func atoi32(s string) (int32, bool) { + if n, ok := atoi(s); n == int(int32(n)) { + return int32(n), ok + } + return 0, false } //go:nosplit -- cgit v1.3-5-g9baa