diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 6e04f50e1d..5738a96a87 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -557,6 +557,14 @@ func (h *mheap) sysAlloc(n uintptr) (v unsafe.Pointer, size uintptr) { } if size == 0 { + if raceenabled { + // The race detector assumes the heap lives in + // [0x00c000000000, 0x00e000000000), but we + // just ran out of hints in this region. Give + // a nice failure. + throw("too many address space collisions for -race mode") + } + // All of the hints failed, so we'll take any // (sufficiently aligned) address the kernel will give // us. diff --git a/src/runtime/malloc_test.go b/src/runtime/malloc_test.go index 854533f238..0bce059f7f 100644 --- a/src/runtime/malloc_test.go +++ b/src/runtime/malloc_test.go @@ -7,6 +7,7 @@ package runtime_test import ( "flag" "fmt" + "internal/race" "internal/testenv" "os" "os/exec" @@ -170,7 +171,17 @@ func TestArenaCollision(t *testing.T) { if os.Getenv("TEST_ARENA_COLLISION") != "1" { cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestArenaCollision", "-test.v")) cmd.Env = append(cmd.Env, "TEST_ARENA_COLLISION=1") - if out, err := cmd.CombinedOutput(); !strings.Contains(string(out), "PASS\n") || err != nil { + out, err := cmd.CombinedOutput() + if race.Enabled { + // This test runs the runtime out of hint + // addresses, so it will start mapping the + // heap wherever it can. The race detector + // doesn't support this, so look for the + // expected failure. + if want := "too many address space collisions"; !strings.Contains(string(out), want) { + t.Fatalf("want %q, got:\n%s", want, string(out)) + } + } else if !strings.Contains(string(out), "PASS\n") || err != nil { t.Fatalf("%s\n(exit status %v)", string(out), err) } return