mirror of https://github.com/gin-gonic/gin.git
Improve the problem described in #1978
In the go, the stack burst will occupy 1G memory, the error message is as follows ```runtime: goroutine stack exceeds 1000000000-byte limit``` If it is a user of gin, the structure of the circular reference is defined on the server side, and the server memory may be used up as long as 100 go processes, and even the server may be down. So I suggest that the mapping function should add a limit on the number of calls, and the number of times can be configured. Of course, I tried several other modifications when I solved the stackoverflow problem described in #1978, but it was not compatible with the existing API, so I did not adopt the solution I tried.
This commit is contained in:
parent
502c898d75
commit
15e9387ca0
|
@ -15,6 +15,8 @@ import (
|
|||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
var LimitMappingCallNumber = 10000
|
||||
|
||||
var errUnknownType = errors.New("Unknown type")
|
||||
|
||||
func mapUri(ptr interface{}, m map[string][]string) error {
|
||||
|
@ -46,11 +48,11 @@ func (form formSource) TrySet(value reflect.Value, field reflect.StructField, ta
|
|||
}
|
||||
|
||||
func mappingByPtr(ptr interface{}, setter setter, tag string) error {
|
||||
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
|
||||
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string, callNumber int) (bool, error) {
|
||||
var vKind = value.Kind()
|
||||
|
||||
if vKind == reflect.Ptr {
|
||||
|
@ -60,7 +62,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||
isNew = true
|
||||
vPtr = reflect.New(value.Type().Elem())
|
||||
}
|
||||
isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
|
||||
isSetted, err := mapping(vPtr.Elem(), field, setter, tag, callNumber+1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -70,6 +72,10 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||
return isSetted, nil
|
||||
}
|
||||
|
||||
if callNumber > LimitMappingCallNumber {
|
||||
return false, errors.New("Maybe entering a circular reference")
|
||||
}
|
||||
|
||||
if vKind != reflect.Struct || !field.Anonymous {
|
||||
ok, err := tryToSetValue(value, field, setter, tag)
|
||||
if err != nil {
|
||||
|
@ -89,7 +95,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue
|
||||
}
|
||||
ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
|
||||
ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag, callNumber+1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue