diff options
| -rw-r--r-- | internal/event/pair.go | 23 | ||||
| -rw-r--r-- | internal/event/pair_test.go | 30 |
2 files changed, 50 insertions, 3 deletions
diff --git a/internal/event/pair.go b/internal/event/pair.go index 4d3f342..c31fd90 100644 --- a/internal/event/pair.go +++ b/internal/event/pair.go @@ -36,12 +36,29 @@ func NewPair(enterEv Event) *Pair { } func (e *Pair) CalculateDurations(prevPairTime uint64) { - // Duration is syscall runtime: exit(current) - enter(current). - e.Duration = e.ExitEv.GetTime() - e.EnterEv.GetTime() + exitTime := e.ExitEv.GetTime() + enterTime := e.EnterEv.GetTime() + + // Guard against uint64 underflow caused by non-monotonic BPF timestamps + // (e.g. cross-CPU clock skew or NTP adjustments). When exit < enter the + // syscall duration cannot be measured reliably; treat it as zero rather + // than wrapping around to an astronomically large value. + if exitTime >= enterTime { + e.Duration = exitTime - enterTime + } else { + e.Duration = 0 + } + if prevPairTime > 0 { // DurationToPrev is the inter-syscall gap on the same TID: // enter(current) - exit(previous). - e.DurationToPrev = e.EnterEv.GetTime() - prevPairTime + // Apply the same underflow guard: if the previous exit timestamp + // is ahead of this enter (clock skew), clamp the gap to zero. + if enterTime >= prevPairTime { + e.DurationToPrev = enterTime - prevPairTime + } else { + e.DurationToPrev = 0 + } } } diff --git a/internal/event/pair_test.go b/internal/event/pair_test.go index eb033dc..9aa3e11 100644 --- a/internal/event/pair_test.go +++ b/internal/event/pair_test.go @@ -56,6 +56,36 @@ func TestPairCalculateDurationsWithPreviousExit(t *testing.T) { } } +// TestPairCalculateDurationsNegativeDelta verifies that non-monotonic BPF +// timestamps (exit < enter due to cross-CPU clock skew) do not cause uint64 +// underflow. Both Duration and DurationToPrev must clamp to zero. +func TestPairCalculateDurationsNegativeDelta(t *testing.T) { + enter := &types.OpenEvent{ + Time: 2000, + Pid: 1, + Tid: 2, + } + // Simulate clock skew: exit timestamp is earlier than enter. + exit := &types.RetEvent{ + Time: 1900, + Pid: 1, + Tid: 2, + Ret: 0, + } + + pair := NewPair(enter) + pair.ExitEv = exit + // prevPairTime > enterTime also triggers underflow in DurationToPrev. + pair.CalculateDurations(3000) + + if pair.Duration != 0 { + t.Fatalf("Duration = %d, want 0 when exit < enter (underflow guard)", pair.Duration) + } + if pair.DurationToPrev != 0 { + t.Fatalf("DurationToPrev = %d, want 0 when enter < prevPairTime (underflow guard)", pair.DurationToPrev) + } +} + func TestPairRecycleHandlesMissingExitEvent(t *testing.T) { pair := NewPair(&types.OpenEvent{ Time: 1000, |
