Source file src/crypto/rand/rand_test.go

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package rand
     6  
     7  import (
     8  	"bytes"
     9  	"compress/flate"
    10  	"crypto/internal/boring"
    11  	"errors"
    12  	"internal/asan"
    13  	"internal/msan"
    14  	"internal/race"
    15  	"internal/testenv"
    16  	"io"
    17  	"os"
    18  	"runtime"
    19  	"sync"
    20  	"testing"
    21  )
    22  
    23  func testReadAndReader(t *testing.T, f func(*testing.T, func([]byte) (int, error))) {
    24  	t.Run("Read", func(t *testing.T) {
    25  		f(t, Read)
    26  	})
    27  	t.Run("Reader.Read", func(t *testing.T) {
    28  		f(t, Reader.Read)
    29  	})
    30  }
    31  
    32  func TestRead(t *testing.T) {
    33  	testReadAndReader(t, testRead)
    34  }
    35  
    36  func testRead(t *testing.T, Read func([]byte) (int, error)) {
    37  	var n int = 4e6
    38  	if testing.Short() {
    39  		n = 1e5
    40  	}
    41  	b := make([]byte, n)
    42  	n, err := Read(b)
    43  	if n != len(b) || err != nil {
    44  		t.Fatalf("Read(buf) = %d, %s", n, err)
    45  	}
    46  
    47  	var z bytes.Buffer
    48  	f, _ := flate.NewWriter(&z, 5)
    49  	f.Write(b)
    50  	f.Close()
    51  	if z.Len() < len(b)*99/100 {
    52  		t.Fatalf("Compressed %d -> %d", len(b), z.Len())
    53  	}
    54  }
    55  
    56  func TestReadByteValues(t *testing.T) {
    57  	testReadAndReader(t, testReadByteValues)
    58  }
    59  
    60  func testReadByteValues(t *testing.T, Read func([]byte) (int, error)) {
    61  	b := make([]byte, 1)
    62  	v := make(map[byte]bool)
    63  	for {
    64  		n, err := Read(b)
    65  		if n != 1 || err != nil {
    66  			t.Fatalf("Read(b) = %d, %v", n, err)
    67  		}
    68  		v[b[0]] = true
    69  		if len(v) == 256 {
    70  			break
    71  		}
    72  	}
    73  }
    74  
    75  func TestLargeRead(t *testing.T) {
    76  	testReadAndReader(t, testLargeRead)
    77  }
    78  
    79  func testLargeRead(t *testing.T, Read func([]byte) (int, error)) {
    80  	// 40MiB, more than the documented maximum of 32Mi-1 on Linux 32-bit.
    81  	b := make([]byte, 40<<20)
    82  	if n, err := Read(b); err != nil {
    83  		t.Fatal(err)
    84  	} else if n != len(b) {
    85  		t.Fatalf("Read(b) = %d, want %d", n, len(b))
    86  	}
    87  }
    88  
    89  func TestReadEmpty(t *testing.T) {
    90  	testReadAndReader(t, testReadEmpty)
    91  }
    92  
    93  func testReadEmpty(t *testing.T, Read func([]byte) (int, error)) {
    94  	n, err := Read(make([]byte, 0))
    95  	if n != 0 || err != nil {
    96  		t.Fatalf("Read(make([]byte, 0)) = %d, %v", n, err)
    97  	}
    98  	n, err = Read(nil)
    99  	if n != 0 || err != nil {
   100  		t.Fatalf("Read(nil) = %d, %v", n, err)
   101  	}
   102  }
   103  
   104  type readerFunc func([]byte) (int, error)
   105  
   106  func (f readerFunc) Read(b []byte) (int, error) {
   107  	return f(b)
   108  }
   109  
   110  func TestReadUsesReader(t *testing.T) {
   111  	var called bool
   112  	defer func(r io.Reader) { Reader = r }(Reader)
   113  	Reader = readerFunc(func(b []byte) (int, error) {
   114  		called = true
   115  		return len(b), nil
   116  	})
   117  	n, err := Read(make([]byte, 32))
   118  	if n != 32 || err != nil {
   119  		t.Fatalf("Read(make([]byte, 32)) = %d, %v", n, err)
   120  	}
   121  	if !called {
   122  		t.Error("Read did not use Reader")
   123  	}
   124  }
   125  
   126  func TestConcurrentRead(t *testing.T) {
   127  	testReadAndReader(t, testConcurrentRead)
   128  }
   129  
   130  func testConcurrentRead(t *testing.T, Read func([]byte) (int, error)) {
   131  	if testing.Short() {
   132  		t.Skip("skipping in short mode")
   133  	}
   134  	const N = 100
   135  	const M = 1000
   136  	var wg sync.WaitGroup
   137  	wg.Add(N)
   138  	for i := 0; i < N; i++ {
   139  		go func() {
   140  			defer wg.Done()
   141  			for i := 0; i < M; i++ {
   142  				b := make([]byte, 32)
   143  				n, err := Read(b)
   144  				if n != 32 || err != nil {
   145  					t.Errorf("Read = %d, %v", n, err)
   146  				}
   147  			}
   148  		}()
   149  	}
   150  	wg.Wait()
   151  }
   152  
   153  var sink byte
   154  
   155  func TestAllocations(t *testing.T) {
   156  	if boring.Enabled {
   157  		// Might be fixable with https://go.dev/issue/56378.
   158  		t.Skip("boringcrypto allocates")
   159  	}
   160  	if race.Enabled || msan.Enabled || asan.Enabled {
   161  		t.Skip("urandomRead allocates under -race, -asan, and -msan")
   162  	}
   163  	if runtime.GOOS == "plan9" {
   164  		t.Skip("plan9 allocates")
   165  	}
   166  	testenv.SkipIfOptimizationOff(t)
   167  
   168  	n := int(testing.AllocsPerRun(10, func() {
   169  		buf := make([]byte, 32)
   170  		Read(buf)
   171  		sink ^= buf[0]
   172  	}))
   173  	if n > 0 {
   174  		t.Errorf("allocs = %d, want 0", n)
   175  	}
   176  }
   177  
   178  // TestNoUrandomFallback ensures the urandom fallback is not reached in
   179  // normal operations.
   180  func TestNoUrandomFallback(t *testing.T) {
   181  	expectFallback := false
   182  	if runtime.GOOS == "aix" {
   183  		// AIX always uses the urandom fallback.
   184  		expectFallback = true
   185  	}
   186  	if os.Getenv("GO_GETRANDOM_DISABLED") == "1" {
   187  		// We are testing the urandom fallback intentionally.
   188  		expectFallback = true
   189  	}
   190  	Read(make([]byte, 1))
   191  	if urandomFile != nil && !expectFallback {
   192  		t.Error("/dev/urandom fallback used unexpectedly")
   193  		t.Log("note: if this test fails, it may be because the system does not have getrandom(2)")
   194  	}
   195  	if urandomFile == nil && expectFallback {
   196  		t.Error("/dev/urandom fallback not used as expected")
   197  	}
   198  }
   199  
   200  func TestReadError(t *testing.T) {
   201  	if testing.Short() {
   202  		t.Skip("skipping test in short mode")
   203  	}
   204  	testenv.MustHaveExec(t)
   205  
   206  	// We run this test in a subprocess because it's expected to crash.
   207  	if os.Getenv("GO_TEST_READ_ERROR") == "1" {
   208  		defer func(r io.Reader) { Reader = r }(Reader)
   209  		Reader = readerFunc(func([]byte) (int, error) {
   210  			return 0, errors.New("error")
   211  		})
   212  		if _, err := Read(make([]byte, 32)); err == nil {
   213  			t.Error("Read did not return error")
   214  		}
   215  		return
   216  	}
   217  
   218  	cmd := testenv.Command(t, os.Args[0], "-test.run=TestReadError")
   219  	cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1")
   220  	out, err := cmd.CombinedOutput()
   221  	if err == nil {
   222  		t.Error("subprocess succeeded unexpectedly")
   223  	}
   224  	exp := "fatal error: crypto/rand: failed to read random data"
   225  	if !bytes.Contains(out, []byte(exp)) {
   226  		t.Errorf("subprocess output does not contain %q: %s", exp, out)
   227  	}
   228  }
   229  
   230  func BenchmarkRead(b *testing.B) {
   231  	b.Run("4", func(b *testing.B) {
   232  		benchmarkRead(b, 4)
   233  	})
   234  	b.Run("32", func(b *testing.B) {
   235  		benchmarkRead(b, 32)
   236  	})
   237  	b.Run("4K", func(b *testing.B) {
   238  		benchmarkRead(b, 4<<10)
   239  	})
   240  }
   241  
   242  func benchmarkRead(b *testing.B, size int) {
   243  	b.SetBytes(int64(size))
   244  	buf := make([]byte, size)
   245  	for i := 0; i < b.N; i++ {
   246  		if _, err := Read(buf); err != nil {
   247  			b.Fatal(err)
   248  		}
   249  	}
   250  }
   251  

View as plain text