Stop using math/rand.Read and rand.Seed (deprecated in Go 1.20)

From golangci-lint:

> SA1019: rand.Read has been deprecated since Go 1.20 because it
>shouldn't be used: For almost all use cases, crypto/rand.Read is more
>appropriate. (staticcheck)

> SA1019: rand.Seed has been deprecated since Go 1.20 and an alternative
>has been available since Go 1.0: Programs that call Seed and then expect
>a specific sequence of results from the global random source (using
>functions such as Int) can be broken when a dependency changes how
>much it consumes from the global random source. To avoid such breakages,
>programs that need a specific result sequence should use
>NewRand(NewSource(seed)) to obtain a random generator that other
>packages cannot access. (staticcheck)

See also:

- https://pkg.go.dev/math/rand@go1.20#Read
- https://pkg.go.dev/math/rand@go1.20#Seed

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2023-02-14 15:32:14 +09:00
parent a9ac5f9cb5
commit d8b68e3ccc
No known key found for this signature in database
GPG Key ID: 49524C6F9F638F1A
17 changed files with 80 additions and 29 deletions

View File

@ -20,8 +20,8 @@ import (
"bytes"
"compress/gzip"
"context"
"crypto/rand"
"io"
"math/rand"
"os"
"path/filepath"
"runtime"

View File

@ -23,12 +23,13 @@ import (
"github.com/containerd/containerd/cmd/containerd/command"
"github.com/containerd/containerd/pkg/hasher"
"github.com/containerd/containerd/pkg/seed"
"github.com/containerd/containerd/pkg/seed" //nolint:staticcheck // Global math/rand seed is deprecated, but still used by external dependencies
_ "github.com/containerd/containerd/cmd/containerd/builtins"
)
func init() {
//nolint:staticcheck // Global math/rand seed is deprecated, but still used by external dependencies
seed.WithTimeAndRand()
crypto.RegisterHash(crypto.SHA256, hasher.NewSHA256)
}

View File

@ -23,13 +23,14 @@ import (
"github.com/containerd/containerd/cmd/ctr/app"
"github.com/containerd/containerd/pkg/hasher"
"github.com/containerd/containerd/pkg/seed"
"github.com/containerd/containerd/pkg/seed" //nolint:staticcheck // Global math/rand seed is deprecated, but still used by external dependencies
"github.com/urfave/cli"
)
var pluginCmds = []cli.Command{}
func init() {
//nolint:staticcheck // Global math/rand seed is deprecated, but still used by external dependencies
seed.WithTimeAndRand()
crypto.RegisterHash(crypto.SHA256, hasher.NewSHA256)
}

View File

@ -21,12 +21,12 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"sync"
"time"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/pkg/randutil"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
@ -123,7 +123,7 @@ func OpenWriter(ctx context.Context, cs Ingester, opts ...WriterOpt) (Writer, er
// error or abort. Requires asserting for an ingest manager
select {
case <-time.After(time.Millisecond * time.Duration(rand.Intn(retry))):
case <-time.After(time.Millisecond * time.Duration(randutil.Intn(retry))):
if retry < 2048 {
retry = retry << 1
}

View File

@ -20,7 +20,6 @@ import (
"context"
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"strconv"
@ -32,6 +31,7 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/filters"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/pkg/randutil"
"github.com/sirupsen/logrus"
"github.com/opencontainers/go-digest"
@ -473,7 +473,7 @@ func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.
lockErr = nil
break
}
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1<<count)))
time.Sleep(time.Millisecond * time.Duration(randutil.Intn(1<<count)))
}
if lockErr != nil {

View File

@ -20,10 +20,10 @@ import (
"bufio"
"bytes"
"context"
"crypto/rand"
_ "crypto/sha256" // required for digest package
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"reflect"
@ -35,6 +35,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/testsuite"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/pkg/randutil"
"github.com/containerd/containerd/pkg/testutil"
"github.com/opencontainers/go-digest"
@ -268,7 +269,7 @@ func generateBlobs(t checker, nblobs, maxsize int64) map[digest.Digest][]byte {
blobs := map[digest.Digest][]byte{}
for i := int64(0); i < nblobs; i++ {
p := make([]byte, rand.Int63n(maxsize))
p := make([]byte, randutil.Int63n(maxsize))
if _, err := rand.Read(p); err != nil {
t.Fatal(err)

View File

@ -18,11 +18,11 @@ package walking
import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"math/rand"
"time"
"github.com/containerd/containerd/archive"

View File

@ -17,9 +17,9 @@
package leases
import (
"crypto/rand"
"encoding/base64"
"fmt"
"math/rand"
"time"
)

View File

@ -19,11 +19,11 @@ package mount
import (
"errors"
"fmt"
"math/rand"
"os"
"strings"
"time"
"github.com/containerd/containerd/pkg/randutil"
"golang.org/x/sys/unix"
)
@ -152,7 +152,7 @@ func setupLoop(backingFile string, param LoopParams) (*os.File, error) {
// with EBUSY when trying to set it up.
if strings.Contains(err.Error(), ebusyString) {
// Fallback a bit to avoid live lock
time.Sleep(time.Millisecond * time.Duration(rand.Intn(retry*10)))
time.Sleep(time.Millisecond * time.Duration(randutil.Intn(retry*10)))
continue
}
return nil, err

View File

@ -17,8 +17,8 @@
package util
import (
"crypto/rand"
"encoding/hex"
"math/rand"
)
// GenerateID generates a random unique id.

View File

@ -18,21 +18,16 @@ package kmutex
import (
"context"
"math/rand"
"runtime"
"strconv"
"sync"
"testing"
"time"
"github.com/containerd/containerd/pkg/seed"
"github.com/containerd/containerd/pkg/randutil"
"github.com/stretchr/testify/assert"
)
func init() {
seed.WithTimeAndRand()
}
func TestBasic(t *testing.T) {
t.Parallel()
@ -60,7 +55,7 @@ func TestBasic(t *testing.T) {
waitLock = true
break
}
time.Sleep(time.Duration(rand.Int63n(100)) * time.Millisecond)
time.Sleep(time.Duration(randutil.Int63n(100)) * time.Millisecond)
}
assert.Equal(t, waitLock, true)
}
@ -130,7 +125,7 @@ func TestMultileAcquireOnKeys(t *testing.T) {
for i := 0; i < nloops; i++ {
km.Lock(ctx, key)
time.Sleep(time.Duration(rand.Int63n(100)) * time.Nanosecond)
time.Sleep(time.Duration(randutil.Int63n(100)) * time.Nanosecond)
km.Unlock(key)
}
@ -161,7 +156,7 @@ func TestMultiAcquireOnSameKey(t *testing.T) {
for i := 0; i < nloops; i++ {
km.Lock(ctx, key)
time.Sleep(time.Duration(rand.Int63n(100)) * time.Nanosecond)
time.Sleep(time.Duration(randutil.Int63n(100)) * time.Nanosecond)
km.Unlock(key)
}

48
pkg/randutil/randutil.go Normal file
View File

@ -0,0 +1,48 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package randutil provides utilities for [cyrpto/rand].
package randutil
import (
"crypto/rand"
"math"
"math/big"
)
// Int63n is similar to [math/rand.Int63n] but uses [crypto/rand.Reader] under the hood.
func Int63n(n int64) int64 {
b, err := rand.Int(rand.Reader, big.NewInt(n))
if err != nil {
panic(err)
}
return b.Int64()
}
// Int63 is similar to [math/rand.Int63] but uses [crypto/rand.Reader] under the hood.
func Int63() int64 {
return Int63n(math.MaxInt64)
}
// Intn is similar to [math/rand.Intn] but uses [crypto/rand.Reader] under the hood.
func Intn(n int) int {
return int(Int63n(int64(n)))
}
// Int is similar to [math/rand.Int] but uses [crypto/rand.Reader] under the hood.
func Int() int {
return int(Int63())
}

View File

@ -14,6 +14,9 @@
limitations under the License.
*/
// Package seed provides an initializer for the global [math/rand] seed.
//
// Deprecated: Do not rely on the global seed.
package seed
import (
@ -23,6 +26,8 @@ import (
// WithTimeAndRand seeds the global math rand generator with nanoseconds
// XOR'ed with a crypto component if available for uniqueness.
//
// Deprecated: Do not rely on the global seed.
func WithTimeAndRand() {
var (
b [4]byte

View File

@ -18,11 +18,11 @@ package unpack
import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"math/rand"
"strconv"
"sync"
"sync/atomic"

View File

@ -18,9 +18,9 @@ package rootfs
import (
"context"
"crypto/rand"
"encoding/base64"
"fmt"
"math/rand"
"time"
"github.com/containerd/containerd/diff"

View File

@ -19,10 +19,10 @@ package testsuite
import (
"context"
"fmt"
"math/rand"
"os"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/pkg/randutil"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/continuity/fs/fstest"
)
@ -49,7 +49,7 @@ func applyToMounts(m []mount.Mount, work string, a fstest.Applier) (err error) {
// createSnapshot creates a new snapshot in the snapshotter
// given an applier to run on top of the given parent.
func createSnapshot(ctx context.Context, sn snapshots.Snapshotter, parent, work string, a fstest.Applier) (string, error) {
n := fmt.Sprintf("%p-%d", a, rand.Int())
n := fmt.Sprintf("%p-%d", a, randutil.Int())
prepare := fmt.Sprintf("%s-prepare", n)
m, err := sn.Prepare(ctx, prepare, parent, opt)

View File

@ -21,7 +21,6 @@ import (
//nolint:revive // go-digest needs the blank import. See https://github.com/opencontainers/go-digest#usage.
_ "crypto/sha256"
"fmt"
"math/rand"
"os"
"path/filepath"
"sort"
@ -32,6 +31,7 @@ import (
"github.com/containerd/containerd/log/logtest"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/pkg/randutil"
"github.com/containerd/containerd/pkg/testutil"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/continuity/fs/fstest"
@ -847,7 +847,7 @@ func checkFileFromLowerLayer(ctx context.Context, t *testing.T, snapshotter snap
}
func closeTwice(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
n := fmt.Sprintf("closeTwice-%d", rand.Int())
n := fmt.Sprintf("closeTwice-%d", randutil.Int())
prepare := fmt.Sprintf("%s-prepare", n)
// do some dummy ops to modify the snapshotter internal state