gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
79.17k stars 8.03k forks source link

Bind recursion struct param fatal exit #3937

Open flyhope opened 7 months ago

flyhope commented 7 months ago

Description

use c.Bind() for recursion struct param, output fatal.

How to reproduce

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
    "net/http/httptest"
)

type ParamA struct {
    B *ParamB
}

type ParamB struct {
    A *ParamA
}

func setupRouter() *gin.Engine {
    r := gin.Default()
    r.GET("/test", func(c *gin.Context) {
        param := new(ParamA)
        if err := c.Bind(param); err != nil {
            panic(err)
        }
        c.JSON(http.StatusOK, param)
    })
    return r
}

func main() {
    router := setupRouter()

    w := httptest.NewRecorder()
    req, _ := http.NewRequest("GET", "/test", nil)
    router.ServeHTTP(w, req)
}

output:

gc 1 @0.021s 2%: 0+4.7+0 ms clock, 0+0/5.3/2.3+0 ms cpu, 3->3->1 MB, 4 MB goal, 8 MB stacks, 0 MB globals, 8 P
gc 2 @0.689s 3%: 0+209+0 ms clock, 0+0/218/21+0 ms cpu, 11->11->6 MB, 12 MB goal, 465 MB stacks, 0 MB globals, 8 P
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0203c1418 stack=[0xc0203c0000, 0xc0403c0000]
fatal error: stack overflow

runtime stack:
runtime.throw({0x1384d2a?, 0x17d69ff7f0?})
    C:/Program Files/Go/src/runtime/panic.go:1023 +0x65 fp=0x17d69ff7b0 sp=0x17d69ff780 pc=0xfdc025
runtime.newstack()
    C:/Program Files/Go/src/runtime/stack.go:1103 +0x5cc fp=0x17d69ff960 sp=0x17d69ff7b0 pc=0xff5e2c
runtime.morestack()
    C:/Program Files/Go/src/runtime/asm_amd64.s:616 +0x79 fp=0x17d69ff968 sp=0x17d69ff960 pc=0x10131b9

goroutine 1 gp=0xc00004e000 m=3 mp=0xc00005b008 [running]:
github.com/gin-gonic/gin/binding.setByForm({0x131d7e0?, 0xc000e7bb08?, 0x199?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:167 +0x47b fp=0xc0203c1428 sp=0xc0203c1420 pc=0x12b4cbb
github.com/gin-gonic/gin/binding.formSource.TrySet(0x0?, {0x131d7e0?, 0xc000e7bb08?, 0x0?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:73 +0x87 fp=0xc0203c14e8 sp=0xc0203c1428 pc=0x12b3e27
github.com/gin-gonic/gin/binding.tryToSetValue({0x131d7e0?, 0xc000e7bb08?, 0x0?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:164 +0x265 fp=0xc0203c15f8 sp=0xc0203c14e8 pc=0x12b47c5
github.com/gin-gonic/gin/binding.mapping({0x131d7e0?, 0xc000e7bb08?, 0x103b14f?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:106 +0x148 fp=0xc0203c1768 sp=0xc0203c15f8 pc=0x12b4168
github.com/gin-gonic/gin/binding.mapping({0x12ec700?, 0xc000e7bb00?, 0x0?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:95 +0x2e5 fp=0xc0203c18d8 sp=0xc0203c1768 pc=0x12b4305
github.com/gin-gonic/gin/binding.mapping({0x131d860?, 0xc000e7bb00?, 0x103b14f?}, {{0x12cf004, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec6c0}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:124 +0x498 fp=0xc0203c1a48 sp=0xc0203c18d8 pc=0x12b44b8
github.com/gin-gonic/gin/binding.mapping({0x12ec6c0?, 0xc000e7baf8?, 0x0?}, {{0x12cf004, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec6c0}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:95 +0x2e5 fp=0xc0203c1bb8 sp=0xc0203c1a48 pc=0x12b4305
github.com/gin-gonic/gin/binding.mapping({0x131d7e0?, 0xc000e7baf8?, 0x103b14f?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:124 +0x498 fp=0xc0203c1d28 sp=0xc0203c1bb8 pc=0x12b44b8
github.com/gin-gonic/gin/binding.mapping({0x12ec700?, 0xc000e7baf0?, 0x0?}, {{0x12cf007, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec700}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:95 +0x2e5 fp=0xc0203c1e98 sp=0xc0203c1d28 pc=0x12b4305
github.com/gin-gonic/gin/binding.mapping({0x131d860?, 0xc000e7baf0?, 0x103b14f?}, {{0x12cf004, 0x1}, {0x0, 0x0}, {0x142f9c0, 0x12ec6c0}, {0x0, ...}, ...}, ...)
    D:/var/GOPATH/pkg/mod/github.com/gin-gonic/gin@v1.9.1/binding/form_mapping.go:124 +0x498 fp=0xc0203c2008 sp=0xc0203c1e98 pc=0x12b44b8

...

Expectations

Don't fatal exit, limit recursion deep number.

Environment

RedCrazyGhost commented 6 months ago

You should not have structs with circular dependencies. You don't conform to the Single Responsibility Principle.