diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-13 10:21:56 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-13 10:21:56 +0300 |
| commit | 7c15d6058cf56e8c7801259f1f842a3a010c5f41 (patch) | |
| tree | 0b9f85dadade5958a281ab6abaa51dcb620603f2 /internal/event/pair_test.go | |
| parent | 42d7821dc8d81781f2c3cfc269e99c0ee1dbd017 (diff) | |
fix: guard Pair.CalculateDurations against uint64 underflow on clock skew
BPF timestamps can be non-monotonic across CPUs (NTP step, TSC skew).
When exit < enter or enter < prevPairTime the uint64 subtraction wraps
to a huge value, corrupting latency histograms and flamegraph weights.
Clamp both Duration and DurationToPrev to 0 instead of underflowing.
Add TestPairCalculateDurationsNegativeDelta to cover this case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/event/pair_test.go')
| -rw-r--r-- | internal/event/pair_test.go | 30 |
1 files changed, 30 insertions, 0 deletions
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, |
