Repository: gin-gonic/gin (language: go)

Issue:
what happened? /github.com/gin-gonic/gin/context.go:173 (0x47f51d3)   (*Context).Next: c.handlers[c.index](c)
what happened
```
	github.com/gin-contrib/expvar v0.0.1
	github.com/gin-contrib/gzip v0.0.5
	github.com/gin-contrib/pprof v1.4.0
	github.com/gin-contrib/sessions v0.0.5
	github.com/gin-contrib/static v0.0.1
	github.com/gin-gonic/gin v1.8.1
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/onsi/ginkgo v1.16.5 // indirect
	google.golang.org/appengine v1.6.7 // indirect
```

code
```
router.Use(func(c *gin.Context) {
		start := time.Now()
		if nil != c {
			c.Next()
		}
		end := time.Now()
		latency := end.Sub(start)

		fmt.Printf("%15s %3d %4s %15s %s\n", latency, c.Writer.Status(), c.Request.Method, c.ClientIP(), c.Request.URL.Path)
	})
```

```
2022/11/18 17:51:08 [Recovery] 2022/11/18 - 17:51:08 panic recovered:
runtime error: invalid memory address or nil pointer dereference
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/panic.go:220 (0x403ac24)
        panicmem: panic(memoryError)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/signal_unix.go:818 (0x405353c)
        sigpanic: panicmem()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51d3)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/pkg/server/sec.go:27 (0x5cebc67)
        InitSecRouter.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/pkg/brotlimd/handler.go:221 (0x5bd20ab)
        (*Handler).Gin: ctx.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/gzip/handler.go:60 (0x5b63304)
        (*gzipHandler).Handle: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/sessions/sessions.go:54 (0x5b6dd37)
        Sessions.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/logger.go:240 (0x4806e31)
        LoggerWithConfig.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/recovery.go:101 (0x4808477)
        CustomRecoveryWithWriter.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:616 (0x4804a28)
        (*Engine).handleHTTPRequest: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:572 (0x48044fa)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/golang.org/x/net/http2/h2c/h2c.go:125 (0x47e3b5b)
        h2cHandler.ServeHTTP: s.Handler.ServeHTTP(w, r)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:2916 (0x44ac813)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:3523 (0x44af6f2)
        initALPNRequest.ServeHTTP: h.h.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/h2_bundle.go:5907 (0x4467a27)
        (*http2serverConn).runHandler: handler(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/asm_amd64.s:1571 (0x4071660)
        goexit: BYTE    $0x90   // NOP

```
what happened? /github.com/gin-gonic/gin/context.go:173 (0x47f51d3)   (*Context).Next: c.handlers[c.index](c)
what happened
```
	github.com/gin-contrib/expvar v0.0.1
	github.com/gin-contrib/gzip v0.0.5
	github.com/gin-contrib/pprof v1.4.0
	github.com/gin-contrib/sessions v0.0.5
	github.com/gin-contrib/static v0.0.1
	github.com/gin-gonic/gin v1.8.1
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/onsi/ginkgo v1.16.5 // indirect
	google.golang.org/appengine v1.6.7 // indirect
```

code
```
router.Use(func(c *gin.Context) {
		start := time.Now()
		if nil != c {
			c.Next()
		}
		end := time.Now()
		latency := end.Sub(start)

		fmt.Printf("%15s %3d %4s %15s %s\n", latency, c.Writer.Status(), c.Request.Method, c.ClientIP(), c.Request.URL.Path)
	})
```

```
2022/11/18 17:51:08 [Recovery] 2022/11/18 - 17:51:08 panic recovered:
runtime error: invalid memory address or nil pointer dereference
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/panic.go:220 (0x403ac24)
        panicmem: panic(memoryError)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/signal_unix.go:818 (0x405353c)
        sigpanic: panicmem()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51d3)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/pkg/server/sec.go:27 (0x5cebc67)
        InitSecRouter.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/pkg/brotlimd/handler.go:221 (0x5bd20ab)
        (*Handler).Gin: ctx.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/gzip/handler.go:60 (0x5b63304)
        (*gzipHandler).Handle: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/sessions/sessions.go:54 (0x5b6dd37)
        Sessions.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/logger.go:240 (0x4806e31)
        LoggerWithConfig.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/recovery.go:101 (0x4808477)
        CustomRecoveryWithWriter.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f51dc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:616 (0x4804a28)
        (*Engine).handleHTTPRequest: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:572 (0x48044fa)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/golang.org/x/net/http2/h2c/h2c.go:125 (0x47e3b5b)
        h2cHandler.ServeHTTP: s.Handler.ServeHTTP(w, r)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:2916 (0x44ac813)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:3523 (0x44af6f2)
        initALPNRequest.ServeHTTP: h.h.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/h2_bundle.go:5907 (0x4467a27)
        (*http2serverConn).runHandler: handler(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/asm_amd64.s:1571 (0x4071660)
        goexit: BYTE    $0x90   // NOP

```


Discussion / hints:
<img width="565" alt="image" src="https://user-images.githubusercontent.com/18223385/202674495-5502224b-afe4-4139-9c70-b2dbfbd5567f.png">

It is recommended to perform nil judgment on the func passed in from use
<img width="873" alt="image" src="https://user-images.githubusercontent.com/18223385/202680137-37e85d57-6397-4a0e-b36b-3a2fc3185aa9.png">
I found some uncertainties. Not every time I find a nil handler, the same exception occurs every time
```
2022/11/18 18:35:39 [Recovery] 2022/11/18 - 18:35:39 panic recovered:
runtime error: invalid memory address or nil pointer dereference
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/panic.go:220 (0x403ad04)
        panicmem: panic(memoryError)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/signal_unix.go:818 (0x405361c)
        sigpanic: panicmem()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52b3)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/pkg/brotlimd/handler.go:221 (0x5bd23cb)
        (*Handler).Gin: ctx.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/gzip/handler.go:60 (0x5b63624)
        (*gzipHandler).Handle: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/sessions/sessions.go:54 (0x5b6e057)
        Sessions.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/logger.go:240 (0x4806f11)
        LoggerWithConfig.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/recovery.go:101 (0x4808557)
        CustomRecoveryWithWriter.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:616 (0x4804b08)
        (*Engine).handleHTTPRequest: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:572 (0x48045da)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/golang.org/x/net/http2/h2c/h2c.go:125 (0x47e3c3b)
        h2cHandler.ServeHTTP: s.Handler.ServeHTTP(w, r)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:2916 (0x44ac8f3)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:3523 (0x44af7d2)
        initALPNRequest.ServeHTTP: h.h.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/h2_bundle.go:5907 (0x4467b07)
        (*http2serverConn).runHandler: handler(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/asm_amd64.s:1571 (0x4071740)
        goexit: BYTE    $0x90   // NOP

```
fix
<img width="615" alt="image" src="https://user-images.githubusercontent.com/18223385/202688064-77fe4db2-e56a-44df-8b17-650bb05b9b42.png">

I checked all the codes, but I never found a place to inject a nil handler



It's amazing
**context.handlers** comes from **value.handlers** (https://github.com/gin-gonic/gin/blob/master/gin.go#L614)
**value.handlers** comes from **node.handlers** (https://github.com/gin-gonic/gin/blob/master/tree.go#L446)
**node.handlers** was initialized in the func addRouter()  https://github.com/gin-gonic/gin/blob/master/tree.go#L152
and the addRouter func is not concurrency-safe.

IDK if you use reset() Context or addRouter() concurrently.

You fix is LGTM.

I hope that would be useful for you!
<img width="565" alt="image" src="https://user-images.githubusercontent.com/18223385/202674495-5502224b-afe4-4139-9c70-b2dbfbd5567f.png">

It is recommended to perform nil judgment on the func passed in from use
<img width="873" alt="image" src="https://user-images.githubusercontent.com/18223385/202680137-37e85d57-6397-4a0e-b36b-3a2fc3185aa9.png">
I found some uncertainties. Not every time I find a nil handler, the same exception occurs every time
```
2022/11/18 18:35:39 [Recovery] 2022/11/18 - 18:35:39 panic recovered:
runtime error: invalid memory address or nil pointer dereference
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/panic.go:220 (0x403ad04)
        panicmem: panic(memoryError)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/signal_unix.go:818 (0x405361c)
        sigpanic: panicmem()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52b3)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/pkg/brotlimd/handler.go:221 (0x5bd23cb)
        (*Handler).Gin: ctx.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/gzip/handler.go:60 (0x5b63624)
        (*gzipHandler).Handle: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-contrib/sessions/sessions.go:54 (0x5b6e057)
        Sessions.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/logger.go:240 (0x4806f11)
        LoggerWithConfig.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/recovery.go:101 (0x4808557)
        CustomRecoveryWithWriter.func1: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/context.go:173 (0x47f52bc)
        (*Context).Next: c.handlers[c.index](c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:616 (0x4804b08)
        (*Engine).handleHTTPRequest: c.Next()
/Users/51pwn/MyWork/goSqlite_gorm/vendor/github.com/gin-gonic/gin/gin.go:572 (0x48045da)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/Users/51pwn/MyWork/goSqlite_gorm/vendor/golang.org/x/net/http2/h2c/h2c.go:125 (0x47e3c3b)
        h2cHandler.ServeHTTP: s.Handler.ServeHTTP(w, r)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:2916 (0x44ac8f3)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/server.go:3523 (0x44af7d2)
        initALPNRequest.ServeHTTP: h.h.ServeHTTP(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/net/http/h2_bundle.go:5907 (0x4467b07)
        (*http2serverConn).runHandler: handler(rw, req)
/usr/local/Cellar/go@1.18/1.18.6/libexec/src/runtime/asm_amd64.s:1571 (0x4071740)
        goexit: BYTE    $0x90   // NOP

```
fix
<img width="615" alt="image" src="https://user-images.githubusercontent.com/18223385/202688064-77fe4db2-e56a-44df-8b17-650bb05b9b42.png">

I checked all the codes, but I never found a place to inject a nil handler



It's amazing
**context.handlers** comes from **value.handlers** (https://github.com/gin-gonic/gin/blob/master/gin.go#L614)
**value.handlers** comes from **node.handlers** (https://github.com/gin-gonic/gin/blob/master/tree.go#L446)
**node.handlers** was initialized in the func addRouter()  https://github.com/gin-gonic/gin/blob/master/tree.go#L152
and the addRouter func is not concurrency-safe.

IDK if you use reset() Context or addRouter() concurrently.

You fix is LGTM.

I hope that would be useful for you!

Fix patch:
diff --git a/context.go b/context.go
index 3525066752..cd2645a93e 100644
--- a/context.go
+++ b/context.go
@@ -152,6 +152,9 @@ func (c *Context) HandlerName() string {
 func (c *Context) HandlerNames() []string {
 	hn := make([]string, 0, len(c.handlers))
 	for _, val := range c.handlers {
+		if val == nil {
+			continue
+		}
 		hn = append(hn, nameOfFunction(val))
 	}
 	return hn
@@ -182,6 +185,9 @@ func (c *Context) FullPath() string {
 func (c *Context) Next() {
 	c.index++
 	for c.index < int8(len(c.handlers)) {
+		if c.handlers[c.index] == nil {
+			continue
+		}
 		c.handlers[c.index](c)
 		c.index++
 	}


Test patch:
diff --git a/context_test.go b/context_test.go
index 36d6e34ac4..517f73e2f6 100644
--- a/context_test.go
+++ b/context_test.go
@@ -362,7 +362,7 @@ func TestContextHandlerName(t *testing.T) {
 
 func TestContextHandlerNames(t *testing.T) {
 	c, _ := CreateTestContext(httptest.NewRecorder())
-	c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest, func(c *Context) {}, handlerNameTest2}
+	c.handlers = HandlersChain{func(c *Context) {}, nil, handlerNameTest, func(c *Context) {}, handlerNameTest2}
 
 	names := c.HandlerNames()
 
@@ -1671,7 +1671,6 @@ func TestContextBindWithXML(t *testing.T) {
 }
 
 func TestContextBindPlain(t *testing.T) {
-
 	// string
 	w := httptest.NewRecorder()
 	c, _ := CreateTestContext(w)
@@ -1863,7 +1862,6 @@ func TestContextShouldBindPlain(t *testing.T) {
 	assert.NoError(t, c.ShouldBindPlain(&bs))
 	assert.Equal(t, []byte("test []byte"), bs)
 	assert.Equal(t, 0, w.Body.Len())
-
 }
 
 func TestContextShouldBindHeader(t *testing.T) {
@@ -2371,6 +2369,7 @@ func TestContextShouldBindBodyWithPlain(t *testing.T) {
 		}
 	}
 }
+
 func TestContextGolangContext(t *testing.T) {
 	c, _ := CreateTestContext(httptest.NewRecorder())
 	c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))