summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-11 07:36:56 +0200
committerPaul Buetow <paul@buetow.org>2026-03-11 07:36:56 +0200
commit1b21e818a69bf73fde3ca60f89d2dc82a79fd605 (patch)
tree0fd55ddc506555a1cc58d804289482265d691414
parent802033de1954bd2fe5e912002fb6c8a07743b66d (diff)
eventloop: factor malformed-event helpers (task 383)
-rw-r--r--internal/eventloop.go166
-rw-r--r--internal/eventloop_error_handling_test.go61
2 files changed, 127 insertions, 100 deletions
diff --git a/internal/eventloop.go b/internal/eventloop.go
index 4b4c0c0..d500350 100644
--- a/internal/eventloop.go
+++ b/internal/eventloop.go
@@ -486,9 +486,8 @@ func (e *eventLoop) initRawHandlers() {
}
e.rawHandlers[types.ENTER_OPEN_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- openEv := types.NewOpenEventFast(raw)
- if openEv == nil {
- e.dropMalformedRawEvent(types.ENTER_OPEN_EVENT, raw)
+ openEv, ok := decodeRawEvent(e, types.ENTER_OPEN_EVENT, raw, types.NewOpenEventFast)
+ if !ok {
return
}
if e.filter.MatchOpenEvent(openEv) {
@@ -496,57 +495,50 @@ func (e *eventLoop) initRawHandlers() {
}
}
e.rawHandlers[types.EXIT_OPEN_EVENT] = func(raw []byte, ch chan<- *event.Pair) {
- retEv := types.NewRetEventFast(raw)
- if retEv == nil {
- e.dropMalformedRawEvent(types.EXIT_OPEN_EVENT, raw)
+ retEv, ok := decodeRawEvent(e, types.EXIT_OPEN_EVENT, raw, types.NewRetEventFast)
+ if !ok {
return
}
e.tracepointExited(retEv, ch)
}
e.rawHandlers[types.ENTER_FD_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- fdEv := types.NewFdEventFast(raw)
- if fdEv == nil {
- e.dropMalformedRawEvent(types.ENTER_FD_EVENT, raw)
+ fdEv, ok := decodeRawEvent(e, types.ENTER_FD_EVENT, raw, types.NewFdEventFast)
+ if !ok {
return
}
e.tracepointEntered(fdEv)
}
e.rawHandlers[types.EXIT_FD_EVENT] = func(raw []byte, ch chan<- *event.Pair) {
- fdEv := types.NewFdEventFast(raw)
- if fdEv == nil {
- e.dropMalformedRawEvent(types.EXIT_FD_EVENT, raw)
+ fdEv, ok := decodeRawEvent(e, types.EXIT_FD_EVENT, raw, types.NewFdEventFast)
+ if !ok {
return
}
e.tracepointExited(fdEv, ch)
}
e.rawHandlers[types.ENTER_NULL_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- nullEv := types.NewNullEventFast(raw)
- if nullEv == nil {
- e.dropMalformedRawEvent(types.ENTER_NULL_EVENT, raw)
+ nullEv, ok := decodeRawEvent(e, types.ENTER_NULL_EVENT, raw, types.NewNullEventFast)
+ if !ok {
return
}
e.tracepointEntered(nullEv)
}
e.rawHandlers[types.EXIT_NULL_EVENT] = func(raw []byte, ch chan<- *event.Pair) {
- nullEv := types.NewNullEventFast(raw)
- if nullEv == nil {
- e.dropMalformedRawEvent(types.EXIT_NULL_EVENT, raw)
+ nullEv, ok := decodeRawEvent(e, types.EXIT_NULL_EVENT, raw, types.NewNullEventFast)
+ if !ok {
return
}
e.tracepointExited(nullEv, ch)
}
e.rawHandlers[types.EXIT_RET_EVENT] = func(raw []byte, ch chan<- *event.Pair) {
- retEv := types.NewRetEventFast(raw)
- if retEv == nil {
- e.dropMalformedRawEvent(types.EXIT_RET_EVENT, raw)
+ retEv, ok := decodeRawEvent(e, types.EXIT_RET_EVENT, raw, types.NewRetEventFast)
+ if !ok {
return
}
e.tracepointExited(retEv, ch)
}
e.rawHandlers[types.ENTER_NAME_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- nameEv := types.NewNameEventFast(raw)
- if nameEv == nil {
- e.dropMalformedRawEvent(types.ENTER_NAME_EVENT, raw)
+ nameEv, ok := decodeRawEvent(e, types.ENTER_NAME_EVENT, raw, types.NewNameEventFast)
+ if !ok {
return
}
if e.filter.MatchNameEvent(nameEv) {
@@ -554,9 +546,8 @@ func (e *eventLoop) initRawHandlers() {
}
}
e.rawHandlers[types.ENTER_PATH_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- pathEv := types.NewPathEventFast(raw)
- if pathEv == nil {
- e.dropMalformedRawEvent(types.ENTER_PATH_EVENT, raw)
+ pathEv, ok := decodeRawEvent(e, types.ENTER_PATH_EVENT, raw, types.NewPathEventFast)
+ if !ok {
return
}
if e.filter.MatchPathEvent(pathEv) {
@@ -564,31 +555,37 @@ func (e *eventLoop) initRawHandlers() {
}
}
e.rawHandlers[types.ENTER_FCNTL_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- fcntlEv := types.NewFcntlEventFast(raw)
- if fcntlEv == nil {
- e.dropMalformedRawEvent(types.ENTER_FCNTL_EVENT, raw)
+ fcntlEv, ok := decodeRawEvent(e, types.ENTER_FCNTL_EVENT, raw, types.NewFcntlEventFast)
+ if !ok {
return
}
e.tracepointEntered(fcntlEv)
}
e.rawHandlers[types.ENTER_OPEN_BY_HANDLE_AT_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- openByHandleEv := types.NewOpenByHandleAtEventFast(raw)
- if openByHandleEv == nil {
- e.dropMalformedRawEvent(types.ENTER_OPEN_BY_HANDLE_AT_EVENT, raw)
+ openByHandleEv, ok := decodeRawEvent(e, types.ENTER_OPEN_BY_HANDLE_AT_EVENT, raw, types.NewOpenByHandleAtEventFast)
+ if !ok {
return
}
e.tracepointEntered(openByHandleEv)
}
e.rawHandlers[types.ENTER_DUP3_EVENT] = func(raw []byte, _ chan<- *event.Pair) {
- dup3Ev := types.NewDup3EventFast(raw)
- if dup3Ev == nil {
- e.dropMalformedRawEvent(types.ENTER_DUP3_EVENT, raw)
+ dup3Ev, ok := decodeRawEvent(e, types.ENTER_DUP3_EVENT, raw, types.NewDup3EventFast)
+ if !ok {
return
}
e.tracepointEntered(dup3Ev)
}
}
+func decodeRawEvent[T any](e *eventLoop, eventType types.EventType, raw []byte, decode func([]byte) *T) (*T, bool) {
+ decoded := decode(raw)
+ if decoded == nil {
+ e.dropMalformedRawEvent(eventType, raw)
+ return nil, false
+ }
+ return decoded, true
+}
+
func (e *eventLoop) tracepointEntered(enterEv event.Event) {
tid := enterEv.GetTid()
// Schedule comm lookup as early as possible to reduce races for short-lived processes.
@@ -649,71 +646,40 @@ func (e *eventLoop) freezePairForEmission(ep *event.Pair) {
func (e *eventLoop) initExitHandlers() {
e.exitHandlers = map[reflect.Type]tracepointExitHandler{
- reflect.TypeOf(&types.OpenEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.OpenEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed open enter event")
- return false
- }
- return e.handleOpenExit(ep, enterEv)
- },
- reflect.TypeOf(&types.NameEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.NameEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed name enter event")
- return false
- }
- return e.handleNameExit(ep, enterEv)
- },
- reflect.TypeOf(&types.PathEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.PathEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed path enter event")
- return false
- }
- return e.handlePathExit(ep, enterEv)
- },
- reflect.TypeOf(&types.FdEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.FdEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed fd enter event")
- return false
- }
- return e.handleFdExit(ep, enterEv)
- },
- reflect.TypeOf(&types.Dup3Event{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.Dup3Event)
- if !ok {
- e.recyclePair(ep, "Dropped malformed dup3 enter event")
- return false
- }
- return e.handleDup3Exit(ep, enterEv)
- },
- reflect.TypeOf(&types.OpenByHandleAtEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.OpenByHandleAtEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed open_by_handle_at enter event")
- return false
- }
- return e.handleOpenByHandleAtExit(ep, enterEv)
- },
- reflect.TypeOf(&types.NullEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.NullEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed null enter event")
- return false
- }
- return e.handleNullExit(ep, enterEv)
- },
- reflect.TypeOf(&types.FcntlEvent{}): func(ep *event.Pair) bool {
- enterEv, ok := ep.EnterEv.(*types.FcntlEvent)
- if !ok {
- e.recyclePair(ep, "Dropped malformed fcntl enter event")
- return false
- }
- return e.handleFcntlExit(ep, enterEv)
- },
+ typeKey[*types.OpenEvent](): newTypedExitHandler(e, "Dropped malformed open enter event", e.handleOpenExit),
+ typeKey[*types.NameEvent](): newTypedExitHandler(e, "Dropped malformed name enter event", e.handleNameExit),
+ typeKey[*types.PathEvent](): newTypedExitHandler(e, "Dropped malformed path enter event", e.handlePathExit),
+ typeKey[*types.FdEvent](): newTypedExitHandler(e, "Dropped malformed fd enter event", e.handleFdExit),
+ typeKey[*types.Dup3Event](): newTypedExitHandler(e, "Dropped malformed dup3 enter event", e.handleDup3Exit),
+ typeKey[*types.OpenByHandleAtEvent](): newTypedExitHandler(e, "Dropped malformed open_by_handle_at enter event", e.handleOpenByHandleAtExit),
+ typeKey[*types.NullEvent](): newTypedExitHandler(e, "Dropped malformed null enter event", e.handleNullExit),
+ typeKey[*types.FcntlEvent](): newTypedExitHandler(e, "Dropped malformed fcntl enter event", e.handleFcntlExit),
+ }
+}
+
+func mustBeType[T event.Event](e *eventLoop, ep *event.Pair, message string) (T, bool) {
+ enterEv, ok := ep.EnterEv.(T)
+ if !ok {
+ e.recyclePair(ep, message)
+ var zero T
+ return zero, false
}
+ return enterEv, true
+}
+
+func newTypedExitHandler[T event.Event](e *eventLoop, message string, handle func(*event.Pair, T) bool) tracepointExitHandler {
+ return func(ep *event.Pair) bool {
+ enterEv, ok := mustBeType[T](e, ep, message)
+ if !ok {
+ return false
+ }
+ return handle(ep, enterEv)
+ }
+}
+
+func typeKey[T any]() reflect.Type {
+ var zero T
+ return reflect.TypeOf(zero)
}
func (e *eventLoop) exitHandlerRegistry() map[reflect.Type]tracepointExitHandler {
diff --git a/internal/eventloop_error_handling_test.go b/internal/eventloop_error_handling_test.go
index b5add72..b7dd282 100644
--- a/internal/eventloop_error_handling_test.go
+++ b/internal/eventloop_error_handling_test.go
@@ -146,6 +146,67 @@ func TestProcessRawEventMalformedKnownTypeDoesNotPanicAndNotifies(t *testing.T)
}
}
+func TestDecodeRawEventMalformedNotifies(t *testing.T) {
+ el := mustNewEventLoop(t, eventLoopConfig{})
+ warnings := make(chan string, 1)
+ el.warningCb = func(message string) { warnings <- message }
+
+ decoded, ok := decodeRawEvent(el, types.ENTER_OPEN_EVENT, []byte{byte(types.ENTER_OPEN_EVENT)}, types.NewOpenEventFast)
+ if ok || decoded != nil {
+ t.Fatalf("expected malformed raw event decode to fail, got ok=%v decoded=%v", ok, decoded)
+ }
+
+ select {
+ case msg := <-warnings:
+ if msg == "" {
+ t.Fatalf("expected non-empty warning message")
+ }
+ default:
+ t.Fatalf("expected warning notification")
+ }
+}
+
+func TestMustBeTypeReturnsTypedEnterEvent(t *testing.T) {
+ el := mustNewEventLoop(t, eventLoopConfig{})
+ enterEv, enterRaw := makeEnterOpenEvent(t, defaulTime, defaultPid, defaultTid)
+ ep := event.NewPair(types.NewOpenEvent(enterRaw))
+ defer ep.Recycle()
+
+ typed, ok := mustBeType[*types.OpenEvent](el, ep, "ignored")
+ if !ok {
+ t.Fatal("expected mustBeType to return the typed enter event")
+ }
+ if typed.GetTid() != enterEv.Tid {
+ t.Fatalf("mustBeType() returned tid %d, want %d", typed.GetTid(), enterEv.Tid)
+ }
+}
+
+func TestMustBeTypeRecyclesMalformedPairAndNotifies(t *testing.T) {
+ el := mustNewEventLoop(t, eventLoopConfig{})
+ warnings := make(chan string, 1)
+ el.warningCb = func(message string) { warnings <- message }
+
+ _, enterRaw := makeEnterNullEvent(t, defaulTime, defaultPid, defaultTid, types.SYS_ENTER_SYNC)
+ ep := event.NewPair(types.NewNullEvent(enterRaw))
+
+ typed, ok := mustBeType[*types.OpenEvent](el, ep, "Dropped malformed open enter event")
+ if ok || typed != nil {
+ t.Fatalf("expected mustBeType mismatch to fail, got ok=%v typed=%v", ok, typed)
+ }
+ if ep.EnterEv != nil || ep.ExitEv != nil {
+ t.Fatalf("expected malformed pair to be recycled")
+ }
+
+ select {
+ case msg := <-warnings:
+ if msg != "Dropped malformed open enter event" {
+ t.Fatalf("unexpected warning %q", msg)
+ }
+ default:
+ t.Fatalf("expected warning notification")
+ }
+}
+
func TestTracepointEnteredMissingCommWithCommFilterNotifies(t *testing.T) {
el := mustNewEventLoop(t, eventLoopConfig{
filter: globalfilter.Filter{