tidwall / redcon

Redis compatible server framework for Go
MIT License
2.16k stars 159 forks source link

race when close redcon #58

Open agfn opened 1 year ago

agfn commented 1 year ago

redcon version: 1.4.4

POC

package main

import (
    "context"
    "log"
    "strings"

    "github.com/go-redis/redis/v9"
    "github.com/tidwall/redcon"
)

func main() {
    redcon := redcon.NewServerNetwork("tcp", "127.0.0.1:12345",
        func(conn redcon.Conn, cmd redcon.Command) {
            switch strings.ToLower(string(cmd.Args[0])) {
            case "set":
                log.Println(string(cmd.Args[1]), string(cmd.Args[2]))
                conn.WriteString("OK")
            default:
                log.Println("cmd not implemented: ", string(cmd.Args[0]))
                conn.WriteError("ERR unknown command '" + string(cmd.Args[0]) + "'")
            }

        }, nil, nil,
    )
    ch := make(chan error)
    go func() {
        redcon.ListenServeAndSignal(ch)
    }()
    if err := <-ch; err != nil {
        log.Fatal(err)
    }

    // create redis client, test set command
    client := redis.NewClient(&redis.Options{
        Addr:    redcon.Addr().String(),
        Network: redcon.Addr().Network(),
    })
    r := client.Set(context.Background(), "tmp", "test", 0)
    if r.Err() != nil {
        log.Fatal(r.Err())
    }
    if err := client.Close(); err != nil {
        log.Fatal(err)
    }

    // close redcon (race)
    if err := redcon.Close(); err != nil {
        log.Fatal(err)
    }
}

// go run -race poc.go

The race occurs when closing redcon while the handle function is not finished (invoking c.wr.Flush, but without lock).

image
tidwall commented 1 year ago

I believe this to be fixed in v1.4.5.