Skip to content

Commit 9b973da

Browse files
wuqinqiangkevwan
authored andcommitted
fix: resolve memory leak in config parsing
1 parent 06502d1 commit 9b973da

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed

core/conf/config.go

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,13 @@ func addOrMergeFields(info *fieldInfo, key string, child *fieldInfo, fullName st
153153
}
154154

155155
func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type, fullName string) error {
156+
return buildAnonymousFieldInfoWithVisited(info, lowerCaseName, ft, fullName, make(map[reflect.Type]bool))
157+
}
158+
159+
func buildAnonymousFieldInfoWithVisited(info *fieldInfo, lowerCaseName string, ft reflect.Type, fullName string, visited map[reflect.Type]bool) error {
156160
switch ft.Kind() {
157161
case reflect.Struct:
158-
fields, err := buildFieldsInfo(ft, fullName)
162+
fields, err := buildFieldsInfoWithVisited(ft, fullName, visited)
159163
if err != nil {
160164
return err
161165
}
@@ -166,7 +170,7 @@ func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.T
166170
}
167171
}
168172
case reflect.Map:
169-
elemField, err := buildFieldsInfo(mapping.Deref(ft.Elem()), fullName)
173+
elemField, err := buildFieldsInfoWithVisited(mapping.Deref(ft.Elem()), fullName, visited)
170174
if err != nil {
171175
return err
172176
}
@@ -193,13 +197,25 @@ func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.T
193197
}
194198

195199
func buildFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error) {
200+
return buildFieldsInfoWithVisited(tp, fullName, make(map[reflect.Type]bool))
201+
}
202+
203+
func buildFieldsInfoWithVisited(tp reflect.Type, fullName string, visited map[reflect.Type]bool) (*fieldInfo, error) {
196204
tp = mapping.Deref(tp)
197205

206+
if visited[tp] {
207+
return &fieldInfo{
208+
children: make(map[string]*fieldInfo),
209+
}, nil
210+
}
211+
198212
switch tp.Kind() {
199213
case reflect.Struct:
200-
return buildStructFieldsInfo(tp, fullName)
214+
visited[tp] = true
215+
defer delete(visited, tp)
216+
return buildStructFieldsInfoWithVisited(tp, fullName, visited)
201217
case reflect.Array, reflect.Slice, reflect.Map:
202-
return buildFieldsInfo(mapping.Deref(tp.Elem()), fullName)
218+
return buildFieldsInfoWithVisited(mapping.Deref(tp.Elem()), fullName, visited)
203219
case reflect.Chan, reflect.Func:
204220
return nil, fmt.Errorf("unsupported type: %s, fullName: %s", tp.Kind(), fullName)
205221
default:
@@ -210,22 +226,26 @@ func buildFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error) {
210226
}
211227

212228
func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type, fullName string) error {
229+
return buildNamedFieldInfoWithVisited(info, lowerCaseName, ft, fullName, make(map[reflect.Type]bool))
230+
}
231+
232+
func buildNamedFieldInfoWithVisited(info *fieldInfo, lowerCaseName string, ft reflect.Type, fullName string, visited map[reflect.Type]bool) error {
213233
var finfo *fieldInfo
214234
var err error
215235

216236
switch ft.Kind() {
217237
case reflect.Struct:
218-
finfo, err = buildFieldsInfo(ft, fullName)
238+
finfo, err = buildFieldsInfoWithVisited(ft, fullName, visited)
219239
if err != nil {
220240
return err
221241
}
222242
case reflect.Array, reflect.Slice:
223-
finfo, err = buildFieldsInfo(ft.Elem(), fullName)
243+
finfo, err = buildFieldsInfoWithVisited(ft.Elem(), fullName, visited)
224244
if err != nil {
225245
return err
226246
}
227247
case reflect.Map:
228-
elemInfo, err := buildFieldsInfo(mapping.Deref(ft.Elem()), fullName)
248+
elemInfo, err := buildFieldsInfoWithVisited(mapping.Deref(ft.Elem()), fullName, visited)
229249
if err != nil {
230250
return err
231251
}
@@ -235,7 +255,7 @@ func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type,
235255
mapField: elemInfo,
236256
}
237257
default:
238-
finfo, err = buildFieldsInfo(ft, fullName)
258+
finfo, err = buildFieldsInfoWithVisited(ft, fullName, visited)
239259
if err != nil {
240260
return err
241261
}
@@ -245,6 +265,10 @@ func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type,
245265
}
246266

247267
func buildStructFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error) {
268+
return buildStructFieldsInfoWithVisited(tp, fullName, make(map[reflect.Type]bool))
269+
}
270+
271+
func buildStructFieldsInfoWithVisited(tp reflect.Type, fullName string, visited map[reflect.Type]bool) (*fieldInfo, error) {
248272
info := &fieldInfo{
249273
children: make(map[string]*fieldInfo),
250274
}
@@ -260,12 +284,12 @@ func buildStructFieldsInfo(tp reflect.Type, fullName string) (*fieldInfo, error)
260284
ft := mapping.Deref(field.Type)
261285
// flatten anonymous fields
262286
if field.Anonymous {
263-
if err := buildAnonymousFieldInfo(info, lowerCaseName, ft,
264-
getFullName(fullName, lowerCaseName)); err != nil {
287+
if err := buildAnonymousFieldInfoWithVisited(info, lowerCaseName, ft,
288+
getFullName(fullName, lowerCaseName), visited); err != nil {
265289
return nil, err
266290
}
267-
} else if err := buildNamedFieldInfo(info, lowerCaseName, ft,
268-
getFullName(fullName, lowerCaseName)); err != nil {
291+
} else if err := buildNamedFieldInfoWithVisited(info, lowerCaseName, ft,
292+
getFullName(fullName, lowerCaseName), visited); err != nil {
269293
return nil, err
270294
}
271295
}

core/mapping/utils.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,25 @@ func ensureValue(v reflect.Value) reflect.Value {
198198
}
199199

200200
func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
201+
return implicitValueRequiredStructWithDepth(tag, tp, 0, make(map[reflect.Type]bool))
202+
}
203+
204+
func implicitValueRequiredStructWithDepth(tag string, tp reflect.Type, depth int, visited map[reflect.Type]bool) (bool, error) {
205+
206+
// max depth to avoid too deep recursion
207+
const maxDepth = 100
208+
if depth > maxDepth {
209+
return false, nil
210+
}
211+
212+
tp = Deref(tp)
213+
if visited[tp] {
214+
return false, nil
215+
}
216+
217+
visited[tp] = true
218+
defer delete(visited, tp)
219+
201220
numFields := tp.NumField()
202221
for i := 0; i < numFields; i++ {
203222
childField := tp.Field(i)
@@ -215,7 +234,7 @@ func implicitValueRequiredStruct(tag string, tp reflect.Type) (bool, error) {
215234
return true, nil
216235
}
217236

218-
if required, err := implicitValueRequiredStruct(tag, childField.Type); err != nil {
237+
if required, err := implicitValueRequiredStructWithDepth(tag, childField.Type, depth+1, visited); err != nil {
219238
return false, err
220239
} else if required {
221240
return true, nil

0 commit comments

Comments
 (0)