From: Martin Möhrmann Date: Sat, 27 Jan 2018 10:55:34 +0000 (+0100) Subject: runtime/internal/math: add multiplication with overflow check X-Git-Tag: go1.12beta1~768 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c9130cae9a9cd59178e842851f3f30b1d97ab0bd;p=gostls13.git runtime/internal/math: add multiplication with overflow check This CL adds a new internal math package for use by the runtime. The new package exports a MulUintptr function with uintptr arguments a and b and returns uintptr(a*b) and whether the full-width product x*y does overflow the uintptr value range (uintptr(x*y) != x*y). Uses of MulUinptr in the runtime and intrinsics for performance will be added in followup CLs. Updates #21588 Change-Id: Ia5a02eeabc955249118e4edf68c67d9fc0858058 Reviewed-on: https://go-review.googlesource.com/c/91755 Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go index a452f2ad29..3fc0fbed1d 100644 --- a/src/cmd/compile/internal/gc/inl_test.go +++ b/src/cmd/compile/internal/gc/inl_test.go @@ -96,6 +96,9 @@ func TestIntendedInlining(t *testing.T) { "(*puintptr).set", }, "runtime/internal/sys": {}, + "runtime/internal/math": { + "MulUintptr", + }, "bytes": { "(*Buffer).Bytes", "(*Buffer).Cap", diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index e8c7fb5b14..8a8b436a23 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -32,7 +32,15 @@ import ( // Do not instrument the following packages at all, // at best instrumentation would cause infinite recursion. -var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan", "internal/cpu"} +var omit_pkgs = []string{ + "runtime/internal/atomic", + "runtime/internal/sys", + "runtime/internal/math", + "runtime", + "runtime/race", + "runtime/msan", + "internal/cpu", +} // Only insert racefuncenterfp/racefuncexit into the following packages. // Memory accesses in the packages are either uninteresting or will cause false positives. diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 91617714f6..904759fe3b 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -36,9 +36,10 @@ var pkgDeps = map[string][]string{ // L0 is the lowest level, core, nearly unavoidable packages. "errors": {}, "io": {"errors", "sync", "sync/atomic"}, - "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "internal/cpu", "internal/bytealg"}, + "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "runtime/internal/math", "internal/cpu", "internal/bytealg"}, "runtime/internal/sys": {}, "runtime/internal/atomic": {"unsafe", "internal/cpu"}, + "runtime/internal/math": {"runtime/internal/sys"}, "internal/race": {"runtime", "unsafe"}, "sync": {"internal/race", "runtime", "sync/atomic", "unsafe"}, "sync/atomic": {"unsafe"}, diff --git a/src/runtime/internal/math/math.go b/src/runtime/internal/math/math.go new file mode 100644 index 0000000000..5385f5dd86 --- /dev/null +++ b/src/runtime/internal/math/math.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import "runtime/internal/sys" + +const MaxUintptr = ^uintptr(0) + +// MulUintptr returns a * b and whether the multiplication overflowed. +// On supported platforms this is an intrinsic lowered by the compiler. +func MulUintptr(a, b uintptr) (uintptr, bool) { + if a|b < 1<<(4*sys.PtrSize) || a == 0 { + return a * b, false + } + overflow := b > MaxUintptr/a + return a * b, overflow +} diff --git a/src/runtime/internal/math/math_test.go b/src/runtime/internal/math/math_test.go new file mode 100644 index 0000000000..9447bd23f9 --- /dev/null +++ b/src/runtime/internal/math/math_test.go @@ -0,0 +1,51 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math_test + +import ( + . "runtime/internal/math" + "testing" +) + +const ( + UintptrSize = 32 << (^uintptr(0) >> 63) +) + +type mulUintptrTest struct { + a uintptr + b uintptr + overflow bool +} + +var mulUintptrTests = []mulUintptrTest{ + {0, 0, false}, + {1000, 1000, false}, + {MaxUintptr, 0, false}, + {MaxUintptr, 1, false}, + {MaxUintptr / 2, 2, false}, + {MaxUintptr / 2, 3, true}, + {MaxUintptr, 10, true}, + {MaxUintptr, 100, true}, + {MaxUintptr / 100, 100, false}, + {MaxUintptr / 1000, 1001, true}, + {1<<(UintptrSize/2) - 1, 1<<(UintptrSize/2) - 1, false}, + {1 << (UintptrSize / 2), 1 << (UintptrSize / 2), true}, + {MaxUintptr >> 32, MaxUintptr >> 32, false}, + {MaxUintptr, MaxUintptr, true}, +} + +func TestMulUintptr(t *testing.T) { + for _, test := range mulUintptrTests { + a, b := test.a, test.b + for i := 0; i < 2; i++ { + mul, overflow := MulUintptr(a, b) + if mul != a*b || overflow != test.overflow { + t.Errorf("MulUintptr(%v, %v) = %v, %v want %v, %v", + a, b, mul, overflow, a*b, test.overflow) + } + a, b = b, a + } + } +}