Closed limpo1989 closed 1 year ago
使用gomonkey配合plugin,实现一个简单的热修复功能会发生崩溃,刚开始patching之后一切正常,运行一会以后就会发生错误
main.go
package main import ( "fmt" "io" "net/http" "os" "plugin" "reflect" "sync/atomic" "time" gomonkey "github.com/agiledragon/gomonkey/v2" "gocase/gopatch/route" ) var HotfixVersion = "main" func IndexHandler() func(http.ResponseWriter, *http.Request) { //return route.Index var counter int32 return func(writer http.ResponseWriter, request *http.Request) { fmt.Fprintln(writer, "plugin handle:", atomic.AddInt32(&counter, 1)) } } func main() { http.HandleFunc("/", route.Index) // 热修复 route.Index 逻辑 { p, err := plugin.Open("http_v1.so") if nil != err { panic(err) } sym, err := p.Lookup("IndexHandler") if nil != err { panic(err) } fn := sym.(func() func(http.ResponseWriter, *http.Request)) handler := fn() fmt.Println("patching...", reflect.ValueOf(route.Index).Pointer(), " => ", reflect.ValueOf(handler).Pointer()) gomonkey.ApplyFunc(route.Index, handler) } // 等3s后开始启动客户端访问接口 time.AfterFunc(time.Second*3, func() { fmt.Println("start client...") for i := 0; i < 3; i++ { go startClient() } }) // 启动http服务器 fmt.Println("http server listen...") err := http.ListenAndServe(":8080", nil) fmt.Println("http server listen failed: ", err) } func startClient() { for { resp, err := http.Get("http://127.0.0.1:8080/") if nil != err { fmt.Println("http.Get: ", err) return } io.Copy(os.Stdout, resp.Body) resp.Body.Close() } }
route.go
var counter int32 func Index(writer http.ResponseWriter, request *http.Request) { fmt.Fprintln(writer, "main: hello gopatch/", atomic.AddInt32(&counter, 1)) }
run_http.sh
#!/bin/bash set -e echo "build main program..." go build -gcflags=all=-l -ldflags="-X main.HotfixVersion=main" -o http_main main.go echo "please modify v1 plugin, press enter key to continue..." read input echo "build plugin v1..." go build -gcflags=all=-l -buildmode=plugin -ldflags="-X main.HotfixVersion=v1" -o http_v1.so main.go echo "run main program..." ./http_main
输出结果
patching... 8606880 => 139904623738208 http server listen... start client... plugin handle: 1 plugin handle: 3 plugin handle: 2 plugin handle: 4 plugin handle: 5 plugin handle: 6 plugin handle: 7 plugin handle: 9 plugin handle: 8 plugin handle: 10 plugin handle: 11 plugin handle: 13 plugin handle: 12 plugin handle: 14 plugin handle: 15 plugin handle: 16 plugin handle: 17 plugin handle: 18 plugin handle: 19 plugin handle: 20 plugin handle: 21 plugin handle: 22 plugin handle: 23 plugin handle: 25 plugin handle: 24 plugin handle: 26 plugin handle: 27 plugin handle: 29 plugin handle: 28 plugin handle: 31 plugin handle: 32 plugin handle: 33 plugin handle: 30 plugin handle: 34 plugin handle: 35 plugin handle: 36 plugin handle: 38 plugin handle: 37 plugin handle: 39 plugin handle: 41 unexpected fault address 0x8dffe8 fatal error: fault plugin handle: 40 [signal SIGSEGV: segmentation violation code=0x2 addr=0x8dffe8 pc=0x8dffe8] goroutine 179 [running]: runtime.throw({0x8d9d5a?, 0xc000016000?}) /usr/local/go/src/runtime/panic.go:1047 +0x5d fp=0xc000206a70 sp=0xc000206a40 pc=0x58e6dd runtime.sigpanic() /usr/local/go/src/runtime/signal_unix.go:851 +0x1e5 fp=0xc000206aa0 sp=0xc000206a70 pc=0x5a5465 net/http.HandlerFunc.ServeHTTP(0x686a65?, {0x929960?, 0xc000344000?}, 0x922938?) /usr/local/go/src/net/http/server.go:2123 +0x2f fp=0xc000206ac8 sp=0xc000206aa0 pc=0x80444f net/http.(*ServeMux).ServeHTTP(0x0?, {0x929960, 0xc000344000}, 0xc0001ce000) /usr/local/go/src/net/http/server.go:2500 +0xc2 fp=0xc000206b00 sp=0xc000206ac8 pc=0x8059a2 net/http.serverHandler.ServeHTTP({0xc00020b3b0?}, {0x929960?, 0xc000344000?}, 0xc0001ce000?) /usr/local/go/src/net/http/server.go:2936 +0x23c fp=0xc000206b98 sp=0xc000206b00 pc=0x806fdc net/http.(*conn).serve(0xc000208f30, {0x929d68, 0xc00011af00}) /usr/local/go/src/net/http/server.go:1995 +0xad0 fp=0xc000206fb8 sp=0xc000206b98 pc=0x8035b0 net/http.(*Server).Serve.func3() /usr/local/go/src/net/http/server.go:3089 +0x2e fp=0xc000206fe0 sp=0xc000206fb8 pc=0x80792e runtime.goexit() /usr/local/go/src/runtime/asm_amd64.s:1598 +0x1 fp=0xc000206fe8 sp=0xc000206fe0 pc=0x5c2861 created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:3089 +0x45f ...
测试环境:
切换为 gohook 后运行正常了,不会崩溃了
使用gomonkey配合plugin,实现一个简单的热修复功能会发生崩溃,刚开始patching之后一切正常,运行一会以后就会发生错误
main.go
route.go
run_http.sh
输出结果