mirror of
https://github.com/golang/go
synced 2024-09-29 07:24:32 -06:00
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 <moehrmann@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
240a30da1b
commit
c9130cae9a
@ -96,6 +96,9 @@ func TestIntendedInlining(t *testing.T) {
|
||||
"(*puintptr).set",
|
||||
},
|
||||
"runtime/internal/sys": {},
|
||||
"runtime/internal/math": {
|
||||
"MulUintptr",
|
||||
},
|
||||
"bytes": {
|
||||
"(*Buffer).Bytes",
|
||||
"(*Buffer).Cap",
|
||||
|
@ -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.
|
||||
|
@ -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"},
|
||||
|
19
src/runtime/internal/math/math.go
Normal file
19
src/runtime/internal/math/math.go
Normal file
@ -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
|
||||
}
|
51
src/runtime/internal/math/math_test.go
Normal file
51
src/runtime/internal/math/math_test.go
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user