netdata CLEAN; telegraf-0001 dedup GetField O(F²) — 1 defect, 1/1 PASS
Netdata: well-engineered with Judy arrays, dictionaries, hash tables throughout. No CWE-407 defects found. Telegraf: dedup processor Apply() calls m.GetField(f.Key) O(F) inside field comparison loop → O(F²). Fix: build field map for O(1) lookup. 125x overhead at F=500.
This commit is contained in:
parent
38634f0b25
commit
27382ae791
4 changed files with 189 additions and 0 deletions
|
|
@ -0,0 +1,44 @@
|
|||
# UNDF: (leave blank)
|
||||
# CWE-407: Dedup processor Apply() uses GetField O(F) inside field loop → O(F²)
|
||||
#
|
||||
# In plugins/processors/dedup/dedup.go, the Apply() method compares each field
|
||||
# of an incoming metric against the cached metric by calling m.GetField(f.Key)
|
||||
# which performs a linear scan of the cached metric's field list. For each
|
||||
# incoming metric, this is O(F_new × F_cached) ≈ O(F²).
|
||||
#
|
||||
# Fix: Build a map from the cached metric's fields for O(1) lookup, reducing
|
||||
# the overall comparison to O(F).
|
||||
#
|
||||
# Severity: MEDIUM — Telegraf metrics typically have 10-50 fields, but
|
||||
# system/CPU/disk metrics can exceed 100 fields. The dedup processor is a
|
||||
# common pipeline component.
|
||||
#
|
||||
--- a/plugins/processors/dedup/dedup.go
|
||||
+++ b/plugins/processors/dedup/dedup.go
|
||||
@@ -31,6 +31,14 @@ func (d *Dedup) Apply(metrics ...telegraf.Metric) []telegraf.Metric {
|
||||
idx := 0
|
||||
for _, metric := range metrics {
|
||||
id := metric.HashID()
|
||||
m, ok := d.cache[id]
|
||||
|
||||
// If not in cache then just save it
|
||||
@@ -53,8 +61,15 @@ func (d *Dedup) Apply(metrics ...telegraf.Metric) []telegraf.Metric {
|
||||
|
||||
// For each field compare value with the cached one
|
||||
changed := false
|
||||
added := false
|
||||
sametime := metric.Time() == m.Time()
|
||||
+
|
||||
+ // Build a map of cached fields for O(1) lookup instead of
|
||||
+ // calling m.GetField() which is O(F) per call
|
||||
+ cachedFields := make(map[string]interface{}, len(m.FieldList()))
|
||||
+ for _, cf := range m.FieldList() {
|
||||
+ cachedFields[cf.Key] = cf.Value
|
||||
+ }
|
||||
+
|
||||
for _, f := range metric.FieldList() {
|
||||
- if value, ok := m.GetField(f.Key); ok {
|
||||
+ if value, ok := cachedFields[f.Key]; ok {
|
||||
if value != f.Value {
|
||||
changed = true
|
||||
break
|
||||
Loading…
Add table
Add a link
Reference in a new issue