-
Notifications
You must be signed in to change notification settings - Fork 10
Description
Summary
Syscall events never call Release() on their eBPF data, causing a memory leak.
Details
In pkg/containerwatcher/v2/container_watcher.go:162-163, syscall events are explicitly skipped from the Release() call:
if enrichedEvent.Event.GetEventType() != utils.SyscallEventType {
enrichedEvent.Event.Release() // at this time we should not need the event anymore
}This was intentional because the syscall tracer (in pkg/containerwatcher/v2/tracers/syscall.go:125-138) creates multiple DatasourceEvents that share the same underlying eBPF Data pointer:
func (st *SyscallTracer) callback(event *utils.DatasourceEvent) {
syscallsBuffer := event.GetSyscalls()
for _, syscall := range decodeSyscalls(syscallsBuffer) {
st.eventCallback(&utils.DatasourceEvent{
Data: event.Data, // WARNING we pass the original data here, not a DeepCopy
Datasource: event.Datasource,
EventType: event.EventType,
Syscall: syscall,
}, containerID, processID)
}
}The comment on line 32 explicitly warns: "WARNING we pass the original data here, not a DeepCopy"
The intent was to avoid calling Release() on one sub-event and freeing data for all sibling events. However, this means the copied eBPF data created at line 112 IS NEVER RELEASED, causing a leak.
Call Chain
syscall.go:112- Initial copy:source.DeepCopy(data)(never released)syscall.go:132- Shared across sub-events:Data: event.Datacontainer_watcher.go:162- Release skipped for ALL syscall events- Memory leaks for every syscall capture
Potential Solutions
-
Deep copy each sub-event (simplest, cleanest)
- In syscall callback:
Data: source.DeepCopy(event.Data), - Remove the skip check at container_watcher.go:162
- Pro: Each event independently owned, consistent with other tracers
- Con: Some memory overhead
- In syscall callback:
-
Add reference counting
- Track number of sub-events sharing each
Datapointer - Release when count reaches zero
- Pro: Shared memory preserved
- Con: More complex, error-prone
- Track number of sub-events sharing each
-
Release in syscall callback
- After syscall loop, call
event.Datasource.Release(event.Data) - Pro: Simple, contained in tracer
- Con: Still violates the "1:1 Release after processing" pattern
- After syscall loop, call
Recommendation: Option 1 — it makes each event independently owned like other tracer types, avoiding shared-data complexity.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status