agiledragon / agiledragon/gomonkey

MacOS m3 打桩失败bug

未关闭
#171 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
主要语言
Go
星标
2.3k
派生
192
平均合并
1 天 6 小时
30 天内合并 PR
1

描述

## 环境
MacOS: 14.6
GO版本: go1.21.13 (也测试了go1.18版本也有问题)
M3芯片
gomonkey版本: v2.12.0
## 问题描述
在一个测试用例中对同一个函数进行打桩、取消、再打桩,后续的打桩可能会失败。以下为测试代码,可以直接拷贝执行验证的
``` golang
type funcValue struct {
_ uintptr
p unsafe.Pointer
}

func getPointer(v reflect.Value) unsafe.Pointer {
return (*funcValue)(unsafe.Pointer(&v)).p
}

func entryAddress(p uintptr, l int) []byte {
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: p, Len: l, Cap: l}))
}

func target() {
fmt.Println("origin func invoked")
}

// func24Byte 此函数将函数对应的代码code前24个字节打印出来,方便观察打桩是否生效了
func func24Byte(fn interface{}) {
v := reflect.ValueOf(fn)
pp := *(*uintptr)(getPointer(v))
addr := entryAddress(pp, 24)
fmt.Printf("代码code:%x\n", addr)
}

func TestBBB(t *testing.T) {
p := gomonkey.NewPatches()
pause := true // 控制每次打桩后是否需要sleep,sleep会影响打桩是否生效,sleep后打桩稳定生效,不sleep打桩不一定会生效
// 输出原始函数
fmt.Println("expect origin func:")
target()
func24Byte(target)

// 第一次打桩
p.ApplyFunc(target, func() {
fmt.Println("double func invoked")
})
if pause {
time.Sleep(time.Millisecond)
}
fmt.Println("expect double func")
target()
func24Byte(target)

// 恢复
p.Reset()
if pause {
time.Sleep(time.Millisecond)
}
fmt.Println("expect origin func")
target()
func24Byte(target)

// 第二次打桩
p2 := gomonkey.NewPatches()
p2.ApplyFunc(target, func() {
fmt.Println("three func invoked")
})
if pause {
time.Sleep(time.Millisecond)
}
fmt.Println("expect three func")
target()
func24Byte(target)

// 恢复
p2.Reset()
if pause {
time.Sleep(time.Millisecond)
}
fmt.Println("expect origin func")
target()
func24Byte(target)
}
```
当使用pause=true 执行测试时,测试完美执行,执行结果如下:
image
但是当运行pause=false时,测试结果如下:
image

我耗费两天观察这个问题,依然百思不得其解,为什么代码区字节码都被改写了,funcValue的调用依然不生效呢,辛苦各位大佬帮忙看下@agiledragon

贡献指南

这个仓库没有索引到贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。