s icon indicating copy to clipboard operation
s copied to clipboard

panic: runtime error: invalid memory address or nil pointer dereference

Open wencan opened this issue 7 years ago • 1 comments

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")
	}

wencan avatar Dec 04 '18 02:12 wencan

os.Setenv("SERVICE_APP", "s1") 意味着以服务的方式启动,这种启动方式会把自己注册到redis,所以需要先启动redis。也可以把这一行注释掉,退化成普通后端。

xujintao avatar Dec 05 '18 03:12 xujintao