Home > Back-end >  Global Variable Gives SIGSEGV
Global Variable Gives SIGSEGV

Time:12-20

I am using Fiber to develop a backend. I have a map that is a global variable that holds the socket connections. When I use the global variable from the same package, no problem here, everything works fine. But, when I try to use the sockets from a route function, I am getting the error below.

I tried to use mutex.lock but no luck.

I checked the code, the socket is not nil in my sendToAll method but it becomes nil in the helper method( inside the lib: github.com/fasthttp/websocket.(*Conn).WriteMessage )

Any advice is welcome.

Thanks.


type ConnectedSocketsContainerType struct {
    M sync.Mutex
    ConnectedSockets map[string]*websocket.Conn
}

var ConnectedSocketsContainer = ConnectedSocketsContainerType{ M:sync.Mutex{} , ConnectedSockets: make(map[string]*websocket.Conn) }

In another package in GET request handler calls that method:

func send(socketID string,message string)  {
    sockethub.ConnectedSocketsContainer.M.Lock()
    sendToAll(message)
    sockethub.ConnectedSocketsContainer.M.Unlock()
}
func sendToAll(message string)  {
    for k := range sockethub.SocketsIDs {
        k.WriteMessage(1, []byte(message))
    }
}

The error:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x14d27f8]

goroutine 6 [running]:
github.com/fasthttp/websocket.(*Conn).WriteMessage(0xc00006aa78, 0xc00045e115, {0xc0004540f0, 0x29, 0xc00006ab2f})
        /Users/emre/go/pkg/mod/github.com/fasthttp/[email protected]/conn.go:753  0x38
goserver/controllers/api.sendToAll({0xc00045e115, 0x29})
        /Users/emre/Documents/Free/SocketServer/goServer/controllers/api/socket.go:11  0xac
goserver/controllers/api.send({0xc000456000, 0x15edfe1}, {0xc00045e115, 0x0})
        /Users/emre/Documents/Free/SocketServer/goServer/controllers/api/socket.go:22  0x65
goserver/controllers/api.SendMessageController(0xc000128a50)
        /Users/emre/Documents/Free/SocketServer/goServer/controllers/api/socket.go:29  0x71
github.com/gofiber/fiber/v2.(*App).next(0xc00019cb60, 0xc000456000)
        /Users/emre/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:127  0x1d8
github.com/gofiber/fiber/v2.(*App).handler(0xc00019cb60, 0x10bb517)
        /Users/emre/go/pkg/mod/github.com/gofiber/fiber/[email protected]/router.go:155  0xe5
github.com/valyala/fasthttp.(*Server).serveConn(0xc000126000, {0x16c4fa0, 0xc0000106e8})
        /Users/emre/go/pkg/mod/github.com/valyala/[email protected]/server.go:2278  0x122d
github.com/valyala/fasthttp.(*workerPool).workerFunc(0xc00014c000, 0xc00022dba0)
        /Users/emre/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:223  0xa9
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
        /Users/emre/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:195  0x38
created by github.com/valyala/fasthttp.(*workerPool).getCh
        /Users/emre/go/pkg/mod/github.com/valyala/[email protected]/workerpool.go:194  0x1b5
exit status 2

Full example for go server. Please see two comments that specify working and not working code blocks.

package main

import (
    "fmt"
    "sync"

    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/websocket/v2"
)

func main() {

    app := fiber.New()

    ListenSocket(app)
    app.Get("/socket/send", SendMessageController )
    app.Listen(":3000")

}
const websocketHeaderKey = "Sec-Websocket-Key"

var ConnectedIDSockets sync.Map 

func SendMessageController( c *fiber.Ctx ) error {
    ConnectedIDSockets.Range(func(key, value interface{}) bool {
        c := value.(*websocket.Conn)
        
        if c == nil {
            // that line is not printed, c is not nil.
            fmt.Println("c is nil.")
            return true
        }

        // we have crash at that line, even we read the err.
        err := c.WriteMessage(websocket.TextMessage, []byte("message"))

        // program does not runs to here since it crashed.
        println("err:", err)
        return true
    })
    return nil
}

func ListenSocket(app *fiber.App) {
    app.Use("/ws", func(c *fiber.Ctx) error {
        if websocket.IsWebSocketUpgrade(c) {
            c.Locals("allowed", true)
            c.Locals(websocketHeaderKey, string(c.Request().Header.Peek(websocketHeaderKey)))
            return c.Next()
        }
        return fiber.ErrUpgradeRequired
    })

    app.Get("/ws/:projectKEY", websocket.New(func(c *websocket.Conn) {

        socketID := c.Locals(websocketHeaderKey).(string)

        ConnectedIDSockets.Store(socketID, c)

        // that works.
        conn, _ := ConnectedIDSockets.Load(socketID)
        socketmap := conn.(*websocket.Conn)
        socketmap.WriteMessage(1, []byte(socketID))

    }))
}

CodePudding user response:

This panic is confusing because there are actually two packages called websocket. One in github.com/gofiber/websocket/v2 and another one in github.com/fasthttp/websocket, and both have their own *websocket.Conn. However the websocket.Conn in github.com/gofiber/websocket actually embeds the websocket.Conn from github.com/fasthttp/websocket (I know, terrible design) making what's going on unclear.

Your call to c.WriteMessage is actually going to c.Conn.WriteMessage, and c.Conn is what's nil. So in your nil check, you actually need to do if c == nil || c.Conn == nil { to check the embedded struct as well.

  • Related