Possible memory leak of the config map array and its C strings in `input.setConfigMap`
- Dominant language
- Go
- Stars
- 202
- Forks
- 61
- Avg merge
- 7d 20h
- Merged PRs (30d)
- 2
Description
# Possible memory leak of the config map array and its C strings in `input.setConfigMap`
`setConfigMap` allocates the config map array plus three C strings per entry, but
`FLBPluginUnregister` only frees `p.name` and `p.description`. The array and all
`3 * len(cmap)` strings are leaked.
input/input.go:112
```go
func setConfigMap(p *FLBPluginProxyDef, cmap []ConfigMap) {
if len(cmap) == 0 {
return
}
cfg := (*C.struct_flb_config_map)(C.calloc(C.size_t(len(cmap)+1), C.sizeof_struct_flb_config_map))
entries := (*[1 << 28]C.struct_flb_config_map)(unsafe.Pointer(cfg))[:len(cmap):len(cmap)]
for i, m := range cmap {
entries[i]._type = C.int(m.Type)
entries[i].name = C.CString(m.Name)
entries[i].flags = C.int(m.Flags)
entries[i].def_value = C.CString(m.DefValue)
entries[i].desc = C.CString(m.Desc)
}
p.config_map = cfg
}
```
input/input.go:131, the function that is supposed to clean this up:
```go
// Release resources allocated by the plugin initialization
func FLBPluginUnregister(def unsafe.Pointer) {
p := (*FLBPluginProxyDef)(def)
C.free(unsafe.Pointer(p.name))
C.free(unsafe.Pointer(p.description))
}
```
Fluent Bit reads the config map during init and does not take ownership of the
allocations, which is why `p.name` and `p.description` are freed here explicitly.
`grep -rn config_map input/` shows only the three lines above, so nothing else releases
them.
This is bounded by the number of plugin registrations rather than by traffic, so it is
one leak per plugin instance rather than growth under load.
Fix: free the entries and the array in `FLBPluginUnregister`. The array is
NUL-terminated by the extra `calloc`ed entry, so it can be walked until `name` is nil:
```go
if p.config_map != nil {
e := (*[1 << 28]C.struct_flb_config_map)(unsafe.Pointer(p.config_map))
for i := 0; e[i].name != nil; i++ {
C.free(unsafe.Pointer(e[i].name))
C.free(unsafe.Pointer(e[i].def_value))
C.free(unsafe.Pointer(e[i].desc))
}
C.free(unsafe.Pointer(p.config_map))
p.config_map = nil
}
```
output/output.go:139 has the same code and the same gap; separate issue for that one.
If you could credit me as a reporter for my contributions to security advisory I will be thankful.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in input/input.go at setConfigMap and FLBPluginUnregister, then inspect the config_map references with the indicated grep command. Verify the plugin-registration lifecycle releases the config-map entries and array without affecting the existing name and description cleanup, and run the repository's tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, go
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100