diff --git a/metrics/internal/lv/labelvalues.go b/metrics/internal/lv/labelvalues.go index 8bb1ba094..d33cda444 100644 --- a/metrics/internal/lv/labelvalues.go +++ b/metrics/internal/lv/labelvalues.go @@ -10,5 +10,10 @@ func (lvs LabelValues) With(labelValues ...string) LabelValues { if len(labelValues)%2 != 0 { labelValues = append(labelValues, "unknown") } - return append(lvs, labelValues...) + // Create a new slice to avoid aliasing the underlying array. + // Without this, sibling With calls (e.g., c1.With("a","1") and + // c1.With("b","2")) can overwrite each other's label values. + result := make(LabelValues, len(lvs), len(lvs)+len(labelValues)) + copy(result, lvs) + return append(result, labelValues...) } diff --git a/metrics/internal/lv/labelvalues_test.go b/metrics/internal/lv/labelvalues_test.go index 5e72609a9..f29d37c44 100644 --- a/metrics/internal/lv/labelvalues_test.go +++ b/metrics/internal/lv/labelvalues_test.go @@ -20,3 +20,17 @@ func TestWith(t *testing.T) { t.Errorf("With does not appear to return the right thing: want %q, have %q", want, have) } } + +func TestWithNoAliasing(t *testing.T) { + base := LabelValues{"a", "1", "b", "2"} + c1 := base.With("c", "3", "d", "4") + c2 := base.With("e", "5") + + // c2 should not have overwritten c1's values + if c1[4] != "c" || c1[5] != "3" { + t.Errorf("c1 was corrupted by sibling With call: got %v", c1) + } + if c2[4] != "e" || c2[5] != "5" { + t.Errorf("c2 has wrong values: got %v", c2) + } +}