enabled by default on listerners. Using multipathtcp="0" reverts to the
pre-Go 1.24 behavior.
+Go 1.24 changed [`crypto/rand.Read`](/pkg/crypto/rand/#Read) to crash the
+program on any error. This setting is controlled by the `randcrash` setting.
+For Go 1.24 it defaults to `randcrash=1`.
+Using `randcrash=0` reverts to the pre-Go 1.24 behavior.
+
### Go 1.23
Go 1.23 changed the channels created by package time to be unbuffered
import (
"crypto/internal/boring"
+ "internal/godebug"
"io"
"os"
"sync"
//go:linkname fatal
func fatal(string)
+var randcrash = godebug.New("randcrash")
+
// Read fills b with cryptographically secure random bytes. It never returns an
// error, and always fills b entirely.
//
copy(b, bb)
}
if err != nil {
+ if randcrash.Value() == "0" {
+ randcrash.IncNonDefault()
+ return 0, err
+ }
fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + err.Error())
panic("unreachable") // To be sure.
}
return
}
- buf := &bytes.Buffer{}
cmd := testenv.Command(t, os.Args[0], "-test.v")
- cmd.Stdout = buf
- cmd.Stderr = buf
cmd.Env = append(os.Environ(), "GO_GETRANDOM_DISABLED=1")
- if err := cmd.Run(); err != nil {
- t.Errorf("subprocess failed: %v\n%s", err, buf.Bytes())
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("subprocess failed: %v\n%s", err, out)
return
}
- if !bytes.Contains(buf.Bytes(), []byte("GetRandom returned ENOSYS")) {
+ if !bytes.Contains(out, []byte("GetRandom returned ENOSYS")) {
t.Errorf("subprocess did not disable getrandom")
}
- if !bytes.Contains(buf.Bytes(), []byte("TestRead")) {
+ if !bytes.Contains(out, []byte("TestRead")) {
t.Errorf("subprocess did not run TestRead")
}
}()
"bytes"
"compress/flate"
"crypto/internal/boring"
+ "errors"
"internal/race"
+ "internal/testenv"
"io"
"os"
"runtime"
}
}
+func TestReadError(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
+ testenv.MustHaveExec(t)
+
+ // We run this test in a subprocess because it's expected to crash the
+ // program unless the GODEBUG is set.
+ if os.Getenv("GO_TEST_READ_ERROR") == "1" {
+ defer func(r io.Reader) { Reader = r }(Reader)
+ Reader = readerFunc(func([]byte) (int, error) {
+ return 0, errors.New("error")
+ })
+ if _, err := Read(make([]byte, 32)); err == nil {
+ t.Error("Read did not return error")
+ }
+ return
+ }
+
+ cmd := testenv.Command(t, os.Args[0], "-test.run=TestReadError")
+ cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1")
+ out, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Error("subprocess succeeded unexpectedly")
+ }
+ exp := "fatal error: crypto/rand: failed to read random data"
+ if !bytes.Contains(out, []byte(exp)) {
+ t.Errorf("subprocess output does not contain %q: %s", exp, out)
+ }
+
+ cmd = testenv.Command(t, os.Args[0], "-test.run=TestReadError")
+ cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1", "GODEBUG=randcrash=0")
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("subprocess failed: %v\n%s", err, out)
+ }
+}
+
func BenchmarkRead(b *testing.B) {
b.Run("4", func(b *testing.B) {
benchmarkRead(b, 4)
{Name: "netedns0", Package: "net", Changed: 19, Old: "0"},
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
{Name: "randautoseed", Package: "math/rand"},
+ {Name: "randcrash", Package: "crypto/rand", Changed: 24, Old: "0"},
{Name: "randseednop", Package: "math/rand", Changed: 24, Old: "0"},
{Name: "tarinsecurepath", Package: "archive/tar"},
{Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"},
The number of non-default behaviors executed by the math/rand
package due to a non-default GODEBUG=randautoseed=... setting.
+ /godebug/non-default-behavior/randcrash:events
+ The number of non-default behaviors executed by the crypto/rand
+ package due to a non-default GODEBUG=randcrash=... setting.
+
/godebug/non-default-behavior/randseednop:events
The number of non-default behaviors executed by the math/rand
package due to a non-default GODEBUG=randseednop=... setting.