Browse Source

pkg: remove random package

The unnecessary `random` package has been removed in favor of using the
`math/rand` package directly. Seeding of the random value from crypto
has been added to the `stringid` package to account for the change.

May need to add an equivalent seed to `namesgenerator`, but this is
often used with `stringid` and has collision protection.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
Stephen J Day 8 năm trước cách đây
mục cha
commit
66cfe61f71

+ 3 - 5
pkg/namesgenerator/names-generator.go

@@ -2,8 +2,7 @@ package namesgenerator
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-
-	"github.com/docker/docker/pkg/random"
+	"math/rand"
 )
 )
 
 
 var (
 var (
@@ -594,15 +593,14 @@ var (
 // formatted as "adjective_surname". For example 'focused_turing'. If retry is non-zero, a random
 // formatted as "adjective_surname". For example 'focused_turing'. If retry is non-zero, a random
 // integer between 0 and 10 will be added to the end of the name, e.g `focused_turing3`
 // integer between 0 and 10 will be added to the end of the name, e.g `focused_turing3`
 func GetRandomName(retry int) string {
 func GetRandomName(retry int) string {
-	rnd := random.Rand
 begin:
 begin:
-	name := fmt.Sprintf("%s_%s", left[rnd.Intn(len(left))], right[rnd.Intn(len(right))])
+	name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
 	if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
 	if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
 		goto begin
 		goto begin
 	}
 	}
 
 
 	if retry > 0 {
 	if retry > 0 {
-		name = fmt.Sprintf("%s%d", name, rnd.Intn(10))
+		name = fmt.Sprintf("%s%d", name, rand.Intn(10))
 	}
 	}
 	return name
 	return name
 }
 }

+ 0 - 71
pkg/random/random.go

@@ -1,71 +0,0 @@
-package random
-
-import (
-	cryptorand "crypto/rand"
-	"io"
-	"math"
-	"math/big"
-	"math/rand"
-	"sync"
-	"time"
-)
-
-// Rand is a global *rand.Rand instance, which initialized with NewSource() source.
-var Rand = rand.New(NewSource())
-
-// Reader is a global, shared instance of a pseudorandom bytes generator.
-// It doesn't consume entropy.
-var Reader io.Reader = &reader{rnd: Rand}
-
-// copypaste from standard math/rand
-type lockedSource struct {
-	lk  sync.Mutex
-	src rand.Source
-}
-
-func (r *lockedSource) Int63() (n int64) {
-	r.lk.Lock()
-	n = r.src.Int63()
-	r.lk.Unlock()
-	return
-}
-
-func (r *lockedSource) Seed(seed int64) {
-	r.lk.Lock()
-	r.src.Seed(seed)
-	r.lk.Unlock()
-}
-
-// NewSource returns math/rand.Source safe for concurrent use and initialized
-// with current unix-nano timestamp
-func NewSource() rand.Source {
-	var seed int64
-	if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil {
-		// This should not happen, but worst-case fallback to time-based seed.
-		seed = time.Now().UnixNano()
-	} else {
-		seed = cryptoseed.Int64()
-	}
-	return &lockedSource{
-		src: rand.NewSource(seed),
-	}
-}
-
-type reader struct {
-	rnd *rand.Rand
-}
-
-func (r *reader) Read(b []byte) (int, error) {
-	i := 0
-	for {
-		val := r.rnd.Int63()
-		for val > 0 {
-			b[i] = byte(val)
-			i++
-			if i == len(b) {
-				return i, nil
-			}
-			val >>= 8
-		}
-	}
-}

+ 0 - 22
pkg/random/random_test.go

@@ -1,22 +0,0 @@
-package random
-
-import (
-	"math/rand"
-	"sync"
-	"testing"
-)
-
-// for go test -v -race
-func TestConcurrency(t *testing.T) {
-	rnd := rand.New(NewSource())
-	var wg sync.WaitGroup
-
-	for i := 0; i < 10; i++ {
-		wg.Add(1)
-		go func() {
-			rnd.Int63()
-			wg.Done()
-		}()
-	}
-	wg.Wait()
-}

+ 28 - 10
pkg/stringid/stringid.go

@@ -2,15 +2,17 @@
 package stringid
 package stringid
 
 
 import (
 import (
-	"crypto/rand"
+	cryptorand "crypto/rand"
 	"encoding/hex"
 	"encoding/hex"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
+	"math"
+	"math/big"
+	"math/rand"
 	"regexp"
 	"regexp"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
-
-	"github.com/docker/docker/pkg/random"
+	"time"
 )
 )
 
 
 const shortLen = 12
 const shortLen = 12
@@ -39,12 +41,8 @@ func TruncateID(id string) string {
 	return id
 	return id
 }
 }
 
 
-func generateID(crypto bool) string {
+func generateID(r io.Reader) string {
 	b := make([]byte, 32)
 	b := make([]byte, 32)
-	r := random.Reader
-	if crypto {
-		r = rand.Reader
-	}
 	for {
 	for {
 		if _, err := io.ReadFull(r, b); err != nil {
 		if _, err := io.ReadFull(r, b); err != nil {
 			panic(err) // This shouldn't happen
 			panic(err) // This shouldn't happen
@@ -62,14 +60,14 @@ func generateID(crypto bool) string {
 
 
 // GenerateRandomID returns a unique id.
 // GenerateRandomID returns a unique id.
 func GenerateRandomID() string {
 func GenerateRandomID() string {
-	return generateID(true)
+	return generateID(cryptorand.Reader)
 }
 }
 
 
 // GenerateNonCryptoID generates unique id without using cryptographically
 // GenerateNonCryptoID generates unique id without using cryptographically
 // secure sources of random.
 // secure sources of random.
 // It helps you to save entropy.
 // It helps you to save entropy.
 func GenerateNonCryptoID() string {
 func GenerateNonCryptoID() string {
-	return generateID(false)
+	return generateID(readerFunc(rand.Read))
 }
 }
 
 
 // ValidateID checks whether an ID string is a valid image ID.
 // ValidateID checks whether an ID string is a valid image ID.
@@ -79,3 +77,23 @@ func ValidateID(id string) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+func init() {
+	// safely set the seed globally so we generate random ids. Tries to use a
+	// crypto seed before falling back to time.
+	var seed int64
+	if cryptoseed, err := cryptorand.Int(cryptorand.Reader, big.NewInt(math.MaxInt64)); err != nil {
+		// This should not happen, but worst-case fallback to time-based seed.
+		seed = time.Now().UnixNano()
+	} else {
+		seed = cryptoseed.Int64()
+	}
+
+	rand.Seed(seed)
+}
+
+type readerFunc func(p []byte) (int, error)
+
+func (fn readerFunc) Read(p []byte) (int, error) {
+	return fn(p)
+}

+ 1 - 3
pkg/stringutils/stringutils.go

@@ -5,8 +5,6 @@ import (
 	"bytes"
 	"bytes"
 	"math/rand"
 	"math/rand"
 	"strings"
 	"strings"
-
-	"github.com/docker/docker/pkg/random"
 )
 )
 
 
 // GenerateRandomAlphaOnlyString generates an alphabetical random string with length n.
 // GenerateRandomAlphaOnlyString generates an alphabetical random string with length n.
@@ -15,7 +13,7 @@ func GenerateRandomAlphaOnlyString(n int) string {
 	letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
 	letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
 	b := make([]byte, n)
 	b := make([]byte, n)
 	for i := range b {
 	for i := range b {
-		b[i] = letters[random.Rand.Intn(len(letters))]
+		b[i] = letters[rand.Intn(len(letters))]
 	}
 	}
 	return string(b)
 	return string(b)
 }
 }