Commit c9130cae authored by Martin Möhrmann's avatar Martin Möhrmann

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: 's avatarKeith Randall <khr@golang.org>
parent 240a30da
...@@ -96,6 +96,9 @@ func TestIntendedInlining(t *testing.T) { ...@@ -96,6 +96,9 @@ func TestIntendedInlining(t *testing.T) {
"(*puintptr).set", "(*puintptr).set",
}, },
"runtime/internal/sys": {}, "runtime/internal/sys": {},
"runtime/internal/math": {
"MulUintptr",
},
"bytes": { "bytes": {
"(*Buffer).Bytes", "(*Buffer).Bytes",
"(*Buffer).Cap", "(*Buffer).Cap",
......
...@@ -32,7 +32,15 @@ import ( ...@@ -32,7 +32,15 @@ import (
// Do not instrument the following packages at all, // Do not instrument the following packages at all,
// at best instrumentation would cause infinite recursion. // 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. // Only insert racefuncenterfp/racefuncexit into the following packages.
// Memory accesses in the packages are either uninteresting or will cause false positives. // Memory accesses in the packages are either uninteresting or will cause false positives.
......
...@@ -36,9 +36,10 @@ var pkgDeps = map[string][]string{ ...@@ -36,9 +36,10 @@ var pkgDeps = map[string][]string{
// L0 is the lowest level, core, nearly unavoidable packages. // L0 is the lowest level, core, nearly unavoidable packages.
"errors": {}, "errors": {},
"io": {"errors", "sync", "sync/atomic"}, "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/sys": {},
"runtime/internal/atomic": {"unsafe", "internal/cpu"}, "runtime/internal/atomic": {"unsafe", "internal/cpu"},
"runtime/internal/math": {"runtime/internal/sys"},
"internal/race": {"runtime", "unsafe"}, "internal/race": {"runtime", "unsafe"},
"sync": {"internal/race", "runtime", "sync/atomic", "unsafe"}, "sync": {"internal/race", "runtime", "sync/atomic", "unsafe"},
"sync/atomic": {"unsafe"}, "sync/atomic": {"unsafe"},
......
// 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
}
// 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
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment