s
s copied to clipboard
panic: runtime error: invalid memory address or nil pointer dereference
go run 下面的代码,触发该bug
package main
import (
"fmt"
"net/http"
"os"
"log"
"github.com/ssgo/s"
)
func main() {
os.Setenv("SERVICE_APP", "s1")
os.Setenv("service_LOGFILE", os.DevNull)
os.Setenv("SERVICE_LISTEN", ":8080")
s.Restful(0, http.MethodGet, "/hello/{name}", func(args map[string]interface{}, w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(os.Stdout, args)
log.Println(r.URL.Path)
fmt.Fprintf(w, "Hello world\n")
})
s.Start1()
}
输出的错误信息:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x7ce6a6]
goroutine 1 [running]:
github.com/ssgo/s.start(0x1, 0x0, 0x0, 0xc0000e3f88)
/home/wencan/Projects/Go/src/github.com/ssgo/s/Server.go:426 +0x27c6
github.com/ssgo/s.Start1()
/home/wencan/Projects/Go/src/github.com/ssgo/s/Server.go:116 +0x33
main.main()
/home/wencan/Projects/main.go:20 +0xff
exit status 2
源码分析:
if err != nil {
Error("S", Map{
"subLogType": "server",
"type": "listenFailed",
"listen": config.Listen,
"error": err.Error(),
})
//log.Print("SERVER ", err)
if as != nil {
as.startChan <- false
}
return err
}
// 这里,err == nil
closeChan := make(chan os.Signal, 2)
signal.Notify(closeChan, os.Interrupt, syscall.SIGTERM)
go func() {
<-closeChan
listener.Close()
}()
addrInfo := listener.Addr().(*net.TCPAddr)
ip := addrInfo.IP
port := addrInfo.Port
if !ip.IsGlobalUnicast() {
// 如果监听的不是外部IP,使用第一个外部IP
addrs, _ := net.InterfaceAddrs()
for _, a := range addrs {
an := a.(*net.IPNet)
// 忽略 Docker 私有网段
if an.IP.IsGlobalUnicast() && !strings.HasPrefix(an.IP.To4().String(), "172.17.") {
ip = an.IP.To4()
}
}
}
serverAddr = fmt.Sprintf("%s:%d", ip.String(), port)
dconf := discover.Config{
Registry: config.Registry,
RegistryAllowTimeout: config.RegistryAllowTimeout,
RegistryPrefix: config.RegistryPrefix,
RegistryCalls: config.RegistryCalls,
App: config.App,
Weight: config.Weight,
CallRetryTimes: config.CallRetryTimes,
XUniqueId: config.XUniqueId,
XForwardedForName: config.XForwardedForName,
XRealIpName: config.XRealIpName,
CallTimeout: config.CallTimeout,
}
calls := map[string]*discover.CallInfo{}
if config.Calls == nil {
config.Calls = map[string]*Call{}
}
for k, v := range config.Calls {
call := discover.CallInfo{
Timeout: v.Timeout,
HttpVersion: v.HttpVersion,
WithSSL: v.WithSSL,
}
call.Headers = map[string]string{}
if v.AccessToken != "" {
call.Headers["Access-Token"] = v.AccessToken
}
if v.Host != "" {
call.Headers["Host"] = v.Host
}
calls[k] = &call
}
dconf.Calls = calls
if discover.Start(serverAddr, dconf) == false {
Error("S", Map{
"subLogType": "server",
"type": "startDiscoverFailed",
"serverAddr": serverAddr,
"error": err.Error(), // panic: runtime error: invalid memory address or nil pointer dereference
})
//log.Printf("SERVER failed to start discover")
listener.Close()
return errors.New("failed to start discover")
}
os.Setenv("SERVICE_APP", "s1") 意味着以服务的方式启动,这种启动方式会把自己注册到redis,所以需要先启动redis。也可以把这一行注释掉,退化成普通后端。