go1.20升級(jí)風(fēng)波...

unexpected?fault?address?0x0
fatal?error:?fault
unexpected?fault?address?0x0
fatal?error:?fault
[signal?SIGSEGV:?segmentation?violation?code=0x80?addr=0x0?pc=0x478dbf]
goroutine?49?[running]:
runtime.throw({0x1f08eaf?,?0x194665d?})
?/usr/local/go/src/runtime/panic.go:1047?+0x5d?fp=0xc0015ad388?sp=0xc0015ad358?pc=0x445afd
runtime.sigpanic()
?/usr/local/go/src/runtime/signal_unix.go:851?+0x28a?fp=0xc0015ad3e8?sp=0xc0015ad388?pc=0x45c82a
aeshashbody()
?/usr/local/go/src/runtime/asm_amd64.s:1370?+0x39f?fp=0xc0015ad3f0?sp=0xc0015ad3e8?pc=0x478dbf
runtime.mapiternext(0xc000cb3200)
?/usr/local/go/src/runtime/map.go:936?+0x2eb?fp=0xc0015ad460?sp=0xc0015ad3f0?pc=0x41eb6b
runtime.mapiterinit(0xc0015ad4f8?,?0xf51c96?,?0x1b57420?)
?/usr/local/go/src/runtime/map.go:863?+0x236?fp=0xc0015ad480?sp=0xc0015ad460?pc=0x41e836
reflect.mapiterinit(0xc0015ad4f8?,?0xf53727?,?0xc000cb3200?)
?/usr/local/go/src/runtime/map.go:1375?+0x19?fp=0xc0015ad4a8?sp=0xc0015ad480?pc=0x474e79
github.com/modern-go/reflect2.(*UnsafeMapType).UnsafeIterate(...)
?/root/go/pkg/mod/github.com/modern-go/[email protected]/unsafe_map.go:112
github.com/json-iterator/go.(*sortKeysMapEncoder).IsEmpty(0xc0015ad570?,?0xc000fe8cd0?)
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/reflect_map.go:333?+0x28?fp=0xc0015ad4e8?sp=0xc0015ad4a8?pc=0xf451c8
github.com/json-iterator/go.(*structFieldEncoder).IsEmpty(0xc001647260,?0x18ab3c2?)
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/reflect_struct_encoder.go:118?+0x42?fp=0xc0015ad508?sp=0xc0015ad4e8?pc=0xf51e42
github.com/json-iterator/go.(*structEncoder).Encode(0xc001647350,?0xc00082a1d8?,?0xc0011b0f60)
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/reflect_struct_encoder.go:148?+0x29b?fp=0xc0015ad5f0?sp=0xc0015ad508?pc=0xf521db
github.com/json-iterator/go.(*OptionalEncoder).Encode(0xc000190320?,?0x0?,?0x0?)
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/reflect_optional.go:70?+0x9d?fp=0xc0015ad640?sp=0xc0015ad5f0?pc=0xf4989d
github.com/json-iterator/go.(*onePtrEncoder).Encode(0xc000722ba0,?0xc000fe8cd0,?0xc000fd35f0?)
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/reflect.go:219?+0x82?fp=0xc0015ad678?sp=0xc0015ad640?pc=0xf3cae2
github.com/json-iterator/go.(*Stream).WriteVal(0xc0011b0f60,?{0x1d20640,?0xc000fe8cd0})
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/reflect.go:98?+0x158?fp=0xc0015ad6e8?sp=0xc0015ad678?pc=0xf3bdf8
github.com/json-iterator/go.(*frozenConfig).Marshal(0xc000190320,?{0x1d20640,?0xc000fe8cd0})
?/root/go/pkg/mod/github.com/json-iterator/[email protected]/config.go:299?+0xc9?fp=0xc0015ad780?sp=0xc0015ad6e8?pc=0xf332a9
今天嘗試把工程從古老的1.13版本升級(jí)到最新的1.20,打算坐下泛型的快車。升級(jí)之后運(yùn)行時(shí)立馬就panic掉了。打印堆棧日志,發(fā)現(xiàn)是內(nèi)部common庫依賴的github.com/json-iterator/[email protected]導(dǎo)致的。翻了翻源碼,問題出在github.com/json-iterator/[email protected]/reflect_map.go:333
type?sortKeysMapEncoder?struct?{
?mapType?????*reflect2.UnsafeMapType
?keyEncoder??ValEncoder
?elemEncoder?ValEncoder
}
func?(encoder?*sortKeysMapEncoder)?IsEmpty(ptr?unsafe.Pointer)?bool?{
?iter?:=?encoder.mapType.UnsafeIterate(ptr)?//line?333
?return?!iter.HasNext()
}
這里的mapType 使用了reflect2(github.com/modern-go/[email protected]),追根溯源
func?(type2?*UnsafeMapType)?UnsafeIterate(obj?unsafe.Pointer)?MapIterator?{
?return?&UnsafeMapIterator{
??hiter:??????mapiterinit(type2.rtype,?*(*unsafe.Pointer)(obj)),//問題根因
??pKeyRType:??type2.pKeyRType,
??pElemRType:?type2.pElemRType,
?}
}
這里reflect2弄了個(gè)騷操作
//?m?escapes?into?the?return?value,?but?the?caller?of?mapiterinit
//?doesn't?let?the?return?value?escape.
//go:noescape
//go:linkname?mapiterinit?reflect.mapiterinit
func?mapiterinit(rtype?unsafe.Pointer,?m?unsafe.Pointer)?*hiter
利用go:linkname這個(gè)編譯器指令,騙過編譯器檢查直接使用了reflect.mapiterinit。其具體含義:
mapiterinit函數(shù)是一個(gè)與reflect包中的mapiterinit函數(shù)相關(guān)聯(lián)的低級(jí)函數(shù),用于初始化 map 的迭代器。它利用了 Go 編譯器的go:linkname指令,以便在reflect2包中直接調(diào)用 Go 運(yùn)行時(shí)(runtime)中實(shí)現(xiàn)的reflect.mapiterinit函數(shù)。
而go1.18版本將reflect.map.iterinit做了調(diào)整
//1.18之前
//?m?escapes?into?the?return?value,?but?the?caller?of?mapiterinit
//?doesn't?let?the?return?value?escape.
//go:noescape
func?mapiterinit(t?*rtype,?m?unsafe.Pointer)?unsafe.Pointer
//1.18
//go:noescape
func?mapiterinit(t?*rtype,?m?unsafe.Pointer,?it?*hiter)
顯然go1.18將mapiterinit新增了一個(gè)參數(shù),但是因?yàn)?code style="font-size:14px;color:rgb(30,107,184);background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;">reflect2使用了騷操作,騙過了編譯器,但運(yùn)行時(shí)panic。
解決辦法:
目前json-iterator和reflect2均已兼容go1.18升級(jí)到最新版本即可
go?get?-u?github.com/json-iterator/go
