bytedance / mockey

a simple and easy-to-use golang mock library
Apache License 2.0
556 stars 22 forks source link

misusage of runtime.sysAlloc may lead to runtime failure in Go 1.19 #13

Closed Sychorius closed 1 year ago

Sychorius commented 1 year ago

Describe the bug

misusage of runtime.sysAlloc may lead to runtime failure in Go 1.19

To Reproduce

run this test in go1.19

func TestSysAlloc(t *testing.T) {
    convey.Convey("sysAlloc", t, func() {
        convey.So(func() {

            data := AllocatePage()

            // try write first and last byte of data
            data[0] = 0
            data[len(data)-1] = 0

            // try get mem stat
            m := runtime.MemStats{}
            runtime.ReadMemStats(&m)

            ReleasePage(data)
        }, convey.ShouldNotPanic)
    })
}

Expected behavior

should not panic

Screenshots image

Mockey version: v1.1.0

Environment: go1.19

Additional context In page.go, mockey pass a virtual memStats to runtime.sysAlloc, which looks ok before go1.19:

func AllocatePage() []byte {
    var memStats uint64 = 0
    addr := sysAlloc(pageSize, &memStats)
    return BytesOf(uintptr(addr), int(memStats))
}

Go 1.19 add some statistics in runtime.sysAlloc , as below:

func sysAlloc(n uintptr, sysStat *sysMemStat) unsafe.Pointer {
    sysStat.add(int64(n))
    gcController.mappedReady.Add(int64(n)) // new feature in go1.19+
    return sysAllocOS(n)
}

When reading memory allocator statistics, which calls runtime.readmemstats_m, it will lead to a crash:

func readmemstats_m(stats *MemStats) {
    ... // some code
       totalMapped := gcController.heapInUse.load() + gcController.heapFree.load() + gcController.heapReleased.load() +
        memstats.stacks_sys.load() + memstats.mspan_sys.load() + memstats.mcache_sys.load() +
        memstats.buckhash_sys.load() + memstats.gcMiscSys.load() + memstats.other_sys.load() +
        stackInUse + gcWorkBufInUse + gcProgPtrScalarBitsInUse
   ... // some code
    if gcController.mappedReady.Load() != totalMapped-uint64(consStats.released) {
        ........ // some code
        throw("mappedReady and other memstats are not equal"). // panic here
    }
   ... // some code
}
ycydsxy commented 1 year ago

interesting