lsg2020 / go-hotfix

runtime monkey patching in Go using plugin / dynamic hotfix / 热更新 / 热修复
32 stars 8 forks source link

热修复之后的函数调用异常 #4

Closed limpo1989 closed 1 year ago

limpo1989 commented 1 year ago

执行热修复之后调用符合期望,但是多次(我这里测试大概2000次调用)进行调用就会开始报异常
下面是我的测试代码,在执行代码之前就进行修复(确保不存在多线程补丁问题)

main.go

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "time"

    hotfix "github.com/lsg2020/go-hotfix"
    "gocase/gofix/route"
)

var HotfixVersion = "main"

func main() {
    http.HandleFunc("/", route.Index)

    // 热修复 route.Index 逻辑
    {
        fmt.Println("start patching...")
        msg, err := hotfix.Hotfix("http_v1.so", []string{"gocase/gofix/route.Index"}, []bool{false}, true)
        if nil != err {
            panic(fmt.Errorf("%w: %s", err, msg))
        }
        fmt.Println("start patching... finished", msg)
    }

    // 等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/index.go

package route

import (
    "fmt"
    "net/http"
    "sync/atomic"
)

var counter int32

func Index(writer http.ResponseWriter, request *http.Request) {
    // 编译插件之前切换下列两行注释,模拟插件逻辑更新
    fmt.Fprintln(writer, "main: hello go-hotfix/", atomic.AddInt32(&counter, 1))
    //fmt.Fprintln(writer, "plugin: hello go-hotfix/", 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

输出结果

plugin: hello go-hotfix/ 2149
plugin: hello go-hotfix/ 2150
plugin: hello go-hotfix/ 2151
plugin: hello go-hotfix/ 2152
plugin: hello go-hotfix/ 2153
plugin: hello go-hotfix/ 2154
plugin: hello go-hotfix/ 2155
plugin: hello go-hotfix/ 2157
plugin: hello go-hotfix/ 2156
plugin: hello go-hotfix/ 2158
2023/05/15 18:06:43 http: panic serving 127.0.0.1:55544: runtime error: invalid memory address or nil pointer dereference
goroutine 2903 [running]:
net/http.(*conn).serve.func1()
        /usr/local/go/src/net/http/server.go:1854 +0xbf
panic({0xb5c0c0, 0xf2cca0})
        /usr/local/go/src/runtime/panic.go:890 +0x262
net/http.HandlerFunc.ServeHTTP(0x778085?, {0xc5c190?, 0xc0001301c0?}, 0xc515d0?)
        /usr/local/go/src/net/http/server.go:2123 +0x2f
net/http.(*ServeMux).ServeHTTP(0x0?, {0xc5c190, 0xc0001301c0}, 0xc000132400)
        /usr/local/go/src/net/http/server.go:2500 +0xc2
net/http.serverHandler.ServeHTTP({0xc0057e2810?}, {0xc5c190?, 0xc0001301c0?}, 0xc000132400?)
        /usr/local/go/src/net/http/server.go:2936 +0x23c
net/http.(*conn).serve(0xc00043a480, {0xc5c7e8, 0xc002320a50})
        /usr/local/go/src/net/http/server.go:1995 +0xad0
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:3089 +0x45f
...
limpo1989 commented 1 year ago

根据测试可以确定问题是 gomonkey 导致的 agiledragon/gomonkey/#132