]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: top align tinyallocs in race mode
authorKeith Randall <khr@golang.org>
Thu, 29 Apr 2021 06:07:38 +0000 (23:07 -0700)
committerKeith Randall <khr@golang.org>
Thu, 29 Apr 2021 17:39:31 +0000 (17:39 +0000)
Top align allocations in tinyalloc buckets when in race mode.
This will make checkptr checks more reliable, because any code
that modifies a pointer past the end of the object will trigger
a checkptr error.

No test, because we need -race for this to actually kick in.  We could
add it to the race detector tests, but the race detector tests are all
geared towards race detector reports, not checkptr reports. Mucking
with parsing reports is more than a test is worth.

Fixes #38872

Change-Id: Ie56f0fbd1a9385539f6631fd1ac40c3de5600154
Reviewed-on: https://go-review.googlesource.com/c/go/+/315029
Trust: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>

src/runtime/export_test.go
src/runtime/malloc.go
src/runtime/malloc_test.go

index f742225d51e926af50fd8fdbcbe84612ef0fe13e..a6fc1e4785f6c7036a454ed345f50d7100fda034 100644 (file)
@@ -1267,3 +1267,5 @@ func GCTestIsReachable(ptrs ...unsafe.Pointer) (mask uint64) {
 func GCTestPointerClass(p unsafe.Pointer) string {
        return gcTestPointerClass(p)
 }
+
+const Raceenabled = raceenabled
index f2d2425f53e54c31e14f6b0152d1cf9c0378a235..3db884f498b00b4b227850c7cd84e65e6f8fe959 100644 (file)
@@ -1047,7 +1047,8 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
                        (*[2]uint64)(x)[1] = 0
                        // See if we need to replace the existing tiny block with the new one
                        // based on amount of remaining free space.
-                       if size < c.tinyoffset || c.tiny == 0 {
+                       if !raceenabled && (size < c.tinyoffset || c.tiny == 0) {
+                               // Note: disabled when race detector is on, see comment near end of this function.
                                c.tiny = uintptr(x)
                                c.tinyoffset = size
                        }
@@ -1165,6 +1166,22 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
                }
        }
 
+       if raceenabled && noscan && dataSize < maxTinySize {
+               // Pad tinysize allocations so they are aligned with the end
+               // of the tinyalloc region. This ensures that any arithmetic
+               // that goes off the top end of the object will be detectable
+               // by checkptr (issue 38872).
+               // Note that we disable tinyalloc when raceenabled for this to work.
+               // TODO: This padding is only performed when the race detector
+               // is enabled. It would be nice to enable it if any package
+               // was compiled with checkptr, but there's no easy way to
+               // detect that (especially at compile time).
+               // TODO: enable this padding for all allocations, not just
+               // tinyalloc ones. It's tricky because of pointer maps.
+               // Maybe just all noscan objects?
+               x = add(x, size-dataSize)
+       }
+
        return x
 }
 
index 4ba94d0494e7d214e553cc6e992c5b814bac293b..e028554b2386d5218194baac291b98a9f6a99149 100644 (file)
@@ -154,6 +154,9 @@ func TestStringConcatenationAllocs(t *testing.T) {
 }
 
 func TestTinyAlloc(t *testing.T) {
+       if runtime.Raceenabled {
+               t.Skip("tinyalloc suppressed when running in race mode")
+       }
        const N = 16
        var v [N]unsafe.Pointer
        for i := range v {
@@ -182,6 +185,9 @@ type obj12 struct {
 }
 
 func TestTinyAllocIssue37262(t *testing.T) {
+       if runtime.Raceenabled {
+               t.Skip("tinyalloc suppressed when running in race mode")
+       }
        // Try to cause an alignment access fault
        // by atomically accessing the first 64-bit
        // value of a tiny-allocated object.