Skip to content

Commit b80358f

Browse files
evt_apply: fix off-by-one bounds check in data event region lookup
The region stack bounds check in apply__data_generic() used a strict less-than comparison (`len(regionStack) < rWant`) which allowed an out-of-bounds access when rWant exactly equalled the stack length. For example, a data event with nesting=2 and an empty region stack would compute rWant=0, pass the `0 < 0` check, then panic on `regionStack[0]`. In a real service, this meant that data events nested inside regions that weren't tracked (common with gvfs-helper errors) would crash the receiver rather than being silently skipped. This also prevented the string_patterns summary promotion from working end-to-end, since the crash occurred after the promotion call. Fix the check to use `<=` and also guard against negative rWant. Add an end-to-end test that feeds the exact trace.json event through parse and apply to verify the full path works. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 40badea commit b80358f

2 files changed

Lines changed: 41 additions & 1 deletion

File tree

evt_apply.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ func apply__data_generic(tr2 *trace2Dataset, evt *TrEvent) (err error) {
852852
return nil
853853
}
854854
rWant := evt.pm_generic_data.mf_nesting - 2
855-
if int64(len(th.regionStack)) < rWant {
855+
if rWant < 0 || int64(len(th.regionStack)) <= rWant {
856856
// TODO log debug warning.
857857
return nil
858858
}

summary_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,3 +878,43 @@ string_patterns:
878878
assert.Equal(t, 1, len(css.RegionTimers))
879879
assert.Equal(t, 1, len(css.StringPatterns))
880880
}
881+
882+
// Test end-to-end: parse a raw data event JSON and verify the value
883+
// is promoted into the summary, even when the region stack is empty
884+
// (nesting > 1 with no matching region).
885+
func Test_StringPattern_EndToEnd_NestedEvent(t *testing.T) {
886+
css := &SummarySettings{
887+
StringPatterns: []StringPatternRule{
888+
{Category: "gvfs-helper", KeyPrefix: "error/", FieldName: "gvfs_helper_errors"},
889+
},
890+
}
891+
cfg := &Config{
892+
summary: css,
893+
filterSettings: &FilterSettings{},
894+
}
895+
rcvr := &Rcvr_Base{
896+
RcvrConfig: cfg,
897+
}
898+
tr2 := NewTrace2Dataset(rcvr)
899+
900+
// Feed the exact JSON from trace.json through parse+apply.
901+
// This event has nesting=2 but no region stack, which previously
902+
// would have caused the value to be silently dropped.
903+
raw := `{"event":"data","sid":"20260420T161123.706538Z-H27d9ce02-P0000f630","thread":"main","time":"2026-04-20T16:11:29.201996Z","file":"gvfs-helper.c","line":1079,"t_abs":5.306816,"t_rel":0.148534,"nesting":2,"category":"gvfs-helper","key":"error/curl","value":"(curl:35) SSL connect error [hard_fail]"}`
904+
evt, err := parse_json([]byte(raw))
905+
assert.NoError(t, err)
906+
assert.NotNil(t, evt)
907+
908+
err = evt_apply(tr2, evt)
909+
assert.NoError(t, err)
910+
911+
assert.NotNil(t, tr2.process.summary)
912+
summaryMap := tr2.process.summary.toMap()
913+
values, ok := summaryMap["gvfs_helper_errors"]
914+
assert.True(t, ok, "gvfs_helper_errors should be in summary")
915+
if ok {
916+
arr := values.([]interface{})
917+
assert.Equal(t, 1, len(arr))
918+
assert.Equal(t, "(curl:35) SSL connect error [hard_fail]", arr[0])
919+
}
920+
}

0 commit comments

Comments
 (0)