diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 8c5ec383f7b2f8..b62b56c9f0a9a8 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -2483,3 +2483,29 @@ func redZoneSize(userSize uintptr) uintptr { return 16 << 7 } } + +// actualSize computes the user allocation size from the total size including redzone. +// Refer to the implementation of the compiler-rt. +func actualSize(allocSize uintptr) uintptr { + if !asanenabled{ + return allocSize + } + switch { + case allocSize > (1<<16) - 1024 + 16<<6: + return allocSize - 16<<7 + case allocSize > (1<<15) - 512 + 16<<5: + return allocSize - 16<<6 + case allocSize > (1<<14) - 256 + 16<<4: + return allocSize - 16<<5 + case allocSize > 4096 - 128 + 16<<3: + return allocSize - 16<<4 + case allocSize > 512 - 64 + 16<<2: + return allocSize - 16<<3 + case allocSize > 128 - 32 + 16<<1: + return allocSize - 16<<2 + case allocSize > 64 - 16 + 16<<0: + return allocSize - 16<<1 + default: + return allocSize - 16<<0 + } +} diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 7c05cd6ea997c1..ac1ab9d93766c1 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -625,6 +625,12 @@ func (span *mspan) writeHeapBitsSmall(x, dataSize uintptr, typ *_type) (scanSize // The objects here are always really small, so a single load is sufficient. src0 := readUintptr(getGCMask(typ)) + // When ASAN is enabled, a redzone is appended to the data, and the redzone would affect + // bitmap calculation by being incorrectly marked as pointers. + srcDataSize := dataSize + if asanenabled { + dataSize = actualSize(srcDataSize) + } // Create repetitions of the bitmap if we have a small slice backing store. src := src0 if typ.Size_ == goarch.PtrSize { @@ -635,7 +641,7 @@ func (span *mspan) writeHeapBitsSmall(x, dataSize uintptr, typ *_type) (scanSize // N.B. We rely on dataSize being an exact multiple of the type size. // The alternative is to be defensive and mask out src to the length // of dataSize. The purpose is to save on one additional masking operation. - if doubleCheckHeapSetType && !asanenabled && dataSize%typ.Size_ != 0 { + if doubleCheckHeapSetType && dataSize%typ.Size_ != 0 { throw("runtime: (*mspan).writeHeapBitsSmall: dataSize is not a multiple of typ.Size_") } scanSize = typ.PtrBytes @@ -643,13 +649,11 @@ func (span *mspan) writeHeapBitsSmall(x, dataSize uintptr, typ *_type) (scanSize src |= src0 << (i / goarch.PtrSize) scanSize += typ.Size_ } - if asanenabled { - // Mask src down to dataSize. dataSize is going to be a strange size because of - // the redzone required for allocations when asan is enabled. - src &= (1 << (dataSize / goarch.PtrSize)) - 1 - } } + if asanenabled { + scanSize += srcDataSize - dataSize + } // Since we're never writing more than one uintptr's worth of bits, we're either going // to do one or two writes. dstBase, _ := spanHeapBitsRange(span.base(), pageSize, span.elemsize) @@ -810,6 +814,9 @@ func doubleCheckHeapType(x, dataSize uintptr, gctyp *_type, header **_type, span maxIterBytes := span.elemsize if header == nil { maxIterBytes = dataSize + if asanenabled { + maxIterBytes = actualSize(dataSize) + } } off := alignUp(uintptr(cheaprand())%dataSize, goarch.PtrSize) size := dataSize - off @@ -836,6 +843,9 @@ func doubleCheckHeapPointers(x, dataSize uintptr, typ *_type, header **_type, sp maxIterBytes := span.elemsize if header == nil { maxIterBytes = dataSize + if asanenabled { + maxIterBytes = actualSize(dataSize) + } } bad := false for i := uintptr(0); i < maxIterBytes; i += goarch.PtrSize {