Open
Description
环境
MacOS: 14.6
GO版本: go1.21.13 (也测试了go1.18版本也有问题)
M3芯片
gomonkey版本: v2.12.0
问题描述
在一个测试用例中对同一个函数进行打桩、取消、再打桩,后续的打桩可能会失败。以下为测试代码,可以直接拷贝执行验证的
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 执行测试时,测试完美执行,执行结果如下:
但是当运行pause=false时,测试结果如下:
我耗费两天观察这个问题,依然百思不得其解,为什么代码区字节码都被改写了,funcValue的调用依然不生效呢,辛苦各位大佬帮忙看下@agiledragon
Metadata
Metadata
Assignees
Labels
No labels