Skip to content

Commit a4cbe78

Browse files
committed
[pdata/pprofile] fix off-by one Dictionary issue
Signed-off-by: Florian Lehner <[email protected]>
1 parent b6dccff commit a4cbe78

19 files changed

Lines changed: 443 additions & 17 deletions

.chloggen/pprofile-off-by-one.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: 'bug_fix'
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. receiver/otlp)
7+
component: pdata/pprofile
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Fix off-by-one issue in dictionary lookups.
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [14534]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

pdata/pprofile/function.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func (fn Function) Equal(val Function) bool {
1717
// dictionary to another.
1818
func (fn Function) switchDictionary(src, dst ProfilesDictionary) error {
1919
if fn.NameStrindex() > 0 {
20-
if src.StringTable().Len() < int(fn.NameStrindex()) {
20+
if src.StringTable().Len() <= int(fn.NameStrindex()) {
2121
return fmt.Errorf("invalid name index %d", fn.NameStrindex())
2222
}
2323

@@ -29,7 +29,7 @@ func (fn Function) switchDictionary(src, dst ProfilesDictionary) error {
2929
}
3030

3131
if fn.SystemNameStrindex() > 0 {
32-
if src.StringTable().Len() < int(fn.SystemNameStrindex()) {
32+
if src.StringTable().Len() <= int(fn.SystemNameStrindex()) {
3333
return fmt.Errorf("invalid system name index %d", fn.SystemNameStrindex())
3434
}
3535

@@ -41,7 +41,7 @@ func (fn Function) switchDictionary(src, dst ProfilesDictionary) error {
4141
}
4242

4343
if fn.FilenameStrindex() > 0 {
44-
if src.StringTable().Len() < int(fn.FilenameStrindex()) {
44+
if src.StringTable().Len() <= int(fn.FilenameStrindex()) {
4545
return fmt.Errorf("invalid filename index %d", fn.FilenameStrindex())
4646
}
4747

pdata/pprofile/function_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,29 @@ func TestFunctionSwitchDictionary(t *testing.T) {
138138
wantDictionary: NewProfilesDictionary(),
139139
wantErr: errors.New("invalid name index 1"),
140140
},
141+
{
142+
name: "with a name index equal to the source table length (boundary condition)",
143+
function: func() Function {
144+
fn := NewFunction()
145+
fn.SetNameStrindex(2) // Index 2 with length 2 (indices 0,1 are valid)
146+
return fn
147+
}(),
148+
149+
src: func() ProfilesDictionary {
150+
d := NewProfilesDictionary()
151+
d.StringTable().Append("", "test") // Length 2: indices 0,1 valid
152+
return d
153+
}(),
154+
dst: NewProfilesDictionary(),
155+
156+
wantFunction: func() Function {
157+
fn := NewFunction()
158+
fn.SetNameStrindex(2)
159+
return fn
160+
}(),
161+
wantDictionary: NewProfilesDictionary(),
162+
wantErr: errors.New("invalid name index 2"),
163+
},
141164
{
142165
name: "with an existing system name",
143166
function: func() Function {
@@ -187,6 +210,29 @@ func TestFunctionSwitchDictionary(t *testing.T) {
187210
wantDictionary: NewProfilesDictionary(),
188211
wantErr: errors.New("invalid system name index 1"),
189212
},
213+
{
214+
name: "with a system name index equal to the source table length (boundary condition)",
215+
function: func() Function {
216+
fn := NewFunction()
217+
fn.SetSystemNameStrindex(2)
218+
return fn
219+
}(),
220+
221+
src: func() ProfilesDictionary {
222+
d := NewProfilesDictionary()
223+
d.StringTable().Append("", "test")
224+
return d
225+
}(),
226+
dst: NewProfilesDictionary(),
227+
228+
wantFunction: func() Function {
229+
fn := NewFunction()
230+
fn.SetSystemNameStrindex(2)
231+
return fn
232+
}(),
233+
wantDictionary: NewProfilesDictionary(),
234+
wantErr: errors.New("invalid system name index 2"),
235+
},
190236
{
191237
name: "with an existing filename",
192238
function: func() Function {
@@ -236,6 +282,29 @@ func TestFunctionSwitchDictionary(t *testing.T) {
236282
wantDictionary: NewProfilesDictionary(),
237283
wantErr: errors.New("invalid filename index 1"),
238284
},
285+
{
286+
name: "with a filename index equal to the source table length (boundary condition)",
287+
function: func() Function {
288+
fn := NewFunction()
289+
fn.SetFilenameStrindex(2)
290+
return fn
291+
}(),
292+
293+
src: func() ProfilesDictionary {
294+
d := NewProfilesDictionary()
295+
d.StringTable().Append("", "test")
296+
return d
297+
}(),
298+
dst: NewProfilesDictionary(),
299+
300+
wantFunction: func() Function {
301+
fn := NewFunction()
302+
fn.SetFilenameStrindex(2)
303+
return fn
304+
}(),
305+
wantDictionary: NewProfilesDictionary(),
306+
wantErr: errors.New("invalid filename index 2"),
307+
},
239308
} {
240309
t.Run(tt.name, func(t *testing.T) {
241310
fn := tt.function

pdata/pprofile/keyvalueandunit.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func (ms KeyValueAndUnit) Equal(val KeyValueAndUnit) bool {
1717
// dictionary to another.
1818
func (ms KeyValueAndUnit) switchDictionary(src, dst ProfilesDictionary) error {
1919
if ms.KeyStrindex() > 0 {
20-
if src.StringTable().Len() < int(ms.KeyStrindex()) {
20+
if src.StringTable().Len() <= int(ms.KeyStrindex()) {
2121
return fmt.Errorf("invalid key index %d", ms.KeyStrindex())
2222
}
2323

@@ -29,7 +29,7 @@ func (ms KeyValueAndUnit) switchDictionary(src, dst ProfilesDictionary) error {
2929
}
3030

3131
if ms.UnitStrindex() > 0 {
32-
if src.StringTable().Len() < int(ms.UnitStrindex()) {
32+
if src.StringTable().Len() <= int(ms.UnitStrindex()) {
3333
return fmt.Errorf("invalid unit index %d", ms.UnitStrindex())
3434
}
3535

pdata/pprofile/keyvalueandunit_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,29 @@ func TestKeyValueAndUnitSwitchDictionary(t *testing.T) {
133133
wantDictionary: NewProfilesDictionary(),
134134
wantErr: errors.New("invalid key index 1"),
135135
},
136+
{
137+
name: "with a key index equal to the source table length (boundary condition)",
138+
keyValueAndUnit: func() KeyValueAndUnit {
139+
kvu := NewKeyValueAndUnit()
140+
kvu.SetKeyStrindex(2)
141+
return kvu
142+
}(),
143+
144+
src: func() ProfilesDictionary {
145+
d := NewProfilesDictionary()
146+
d.StringTable().Append("", "test")
147+
return d
148+
}(),
149+
dst: NewProfilesDictionary(),
150+
151+
wantKeyValueAndUnit: func() KeyValueAndUnit {
152+
kvu := NewKeyValueAndUnit()
153+
kvu.SetKeyStrindex(2)
154+
return kvu
155+
}(),
156+
wantDictionary: NewProfilesDictionary(),
157+
wantErr: errors.New("invalid key index 2"),
158+
},
136159
{
137160
name: "with an existing unit",
138161
keyValueAndUnit: func() KeyValueAndUnit {
@@ -182,6 +205,29 @@ func TestKeyValueAndUnitSwitchDictionary(t *testing.T) {
182205
wantDictionary: NewProfilesDictionary(),
183206
wantErr: errors.New("invalid unit index 1"),
184207
},
208+
{
209+
name: "with a unit index equal to the source table length (boundary condition)",
210+
keyValueAndUnit: func() KeyValueAndUnit {
211+
kvu := NewKeyValueAndUnit()
212+
kvu.SetUnitStrindex(2)
213+
return kvu
214+
}(),
215+
216+
src: func() ProfilesDictionary {
217+
d := NewProfilesDictionary()
218+
d.StringTable().Append("", "test")
219+
return d
220+
}(),
221+
dst: NewProfilesDictionary(),
222+
223+
wantKeyValueAndUnit: func() KeyValueAndUnit {
224+
kvu := NewKeyValueAndUnit()
225+
kvu.SetUnitStrindex(2)
226+
return kvu
227+
}(),
228+
wantDictionary: NewProfilesDictionary(),
229+
wantErr: errors.New("invalid unit index 2"),
230+
},
185231
} {
186232
t.Run(tt.name, func(t *testing.T) {
187233
kvu := tt.keyValueAndUnit

pdata/pprofile/line.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (l Line) Equal(val Line) bool {
3131
// dictionary to another.
3232
func (l Line) switchDictionary(src, dst ProfilesDictionary) error {
3333
if l.FunctionIndex() > 0 {
34-
if src.FunctionTable().Len() < int(l.FunctionIndex()) {
34+
if src.FunctionTable().Len() <= int(l.FunctionIndex()) {
3535
return fmt.Errorf("invalid function index %d", l.FunctionIndex())
3636
}
3737

pdata/pprofile/line_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,30 @@ func TestLineSwitchDictionary(t *testing.T) {
206206
wantDictionary: NewProfilesDictionary(),
207207
wantErr: errors.New("invalid function index 1"),
208208
},
209+
{
210+
name: "with a function index equal to the source table length (boundary condition)",
211+
line: func() Line {
212+
l := NewLine()
213+
l.SetFunctionIndex(2)
214+
return l
215+
}(),
216+
217+
src: func() ProfilesDictionary {
218+
d := NewProfilesDictionary()
219+
d.FunctionTable().AppendEmpty()
220+
d.FunctionTable().AppendEmpty() // Length 2: indices 0,1 valid
221+
return d
222+
}(),
223+
dst: NewProfilesDictionary(),
224+
225+
wantLine: func() Line {
226+
l := NewLine()
227+
l.SetFunctionIndex(2)
228+
return l
229+
}(),
230+
wantDictionary: NewProfilesDictionary(),
231+
wantErr: errors.New("invalid function index 2"),
232+
},
209233
} {
210234
t.Run(tt.name, func(t *testing.T) {
211235
line := tt.line

pdata/pprofile/location.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func (ms Location) Equal(val Location) bool {
1717
// dictionary to another.
1818
func (ms Location) switchDictionary(src, dst ProfilesDictionary) error {
1919
if ms.MappingIndex() > 0 {
20-
if src.MappingTable().Len() < int(ms.MappingIndex()) {
20+
if src.MappingTable().Len() <= int(ms.MappingIndex()) {
2121
return fmt.Errorf("invalid mapping index %d", ms.MappingIndex())
2222
}
2323

@@ -34,7 +34,7 @@ func (ms Location) switchDictionary(src, dst ProfilesDictionary) error {
3434
}
3535

3636
for i, v := range ms.AttributeIndices().All() {
37-
if src.AttributeTable().Len() < int(v) {
37+
if src.AttributeTable().Len() <= int(v) {
3838
return fmt.Errorf("invalid attribute index %d", v)
3939
}
4040

pdata/pprofile/location_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,30 @@ func TestLocationSwitchDictionary(t *testing.T) {
150150
wantDictionary: NewProfilesDictionary(),
151151
wantErr: errors.New("invalid mapping index 1"),
152152
},
153+
{
154+
name: "with a mapping index equal to the source table length (boundary condition)",
155+
location: func() Location {
156+
l := NewLocation()
157+
l.SetMappingIndex(2)
158+
return l
159+
}(),
160+
161+
src: func() ProfilesDictionary {
162+
d := NewProfilesDictionary()
163+
d.MappingTable().AppendEmpty()
164+
d.MappingTable().AppendEmpty()
165+
return d
166+
}(),
167+
dst: NewProfilesDictionary(),
168+
169+
wantLocation: func() Location {
170+
l := NewLocation()
171+
l.SetMappingIndex(2)
172+
return l
173+
}(),
174+
wantDictionary: NewProfilesDictionary(),
175+
wantErr: errors.New("invalid mapping index 2"),
176+
},
153177
{
154178
name: "with an existing attribute",
155179
location: func() Location {
@@ -212,6 +236,30 @@ func TestLocationSwitchDictionary(t *testing.T) {
212236
wantDictionary: NewProfilesDictionary(),
213237
wantErr: errors.New("invalid attribute index 1"),
214238
},
239+
{
240+
name: "with an attribute index equal to the source table length (boundary condition)",
241+
location: func() Location {
242+
l := NewLocation()
243+
l.AttributeIndices().Append(2)
244+
return l
245+
}(),
246+
247+
src: func() ProfilesDictionary {
248+
d := NewProfilesDictionary()
249+
d.AttributeTable().AppendEmpty()
250+
d.AttributeTable().AppendEmpty()
251+
return d
252+
}(),
253+
dst: NewProfilesDictionary(),
254+
255+
wantLocation: func() Location {
256+
l := NewLocation()
257+
l.AttributeIndices().Append(2)
258+
return l
259+
}(),
260+
wantDictionary: NewProfilesDictionary(),
261+
wantErr: errors.New("invalid attribute index 2"),
262+
},
215263
{
216264
name: "with an existing line",
217265
location: func() Location {

pdata/pprofile/mapping.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func (ms Mapping) Equal(val Mapping) bool {
1818
// dictionary to another.
1919
func (ms Mapping) switchDictionary(src, dst ProfilesDictionary) error {
2020
if ms.FilenameStrindex() > 0 {
21-
if src.StringTable().Len() < int(ms.FilenameStrindex()) {
21+
if src.StringTable().Len() <= int(ms.FilenameStrindex()) {
2222
return fmt.Errorf("invalid filename index %d", ms.FilenameStrindex())
2323
}
2424

@@ -30,7 +30,7 @@ func (ms Mapping) switchDictionary(src, dst ProfilesDictionary) error {
3030
}
3131

3232
for i, v := range ms.AttributeIndices().All() {
33-
if src.AttributeTable().Len() < int(v) {
33+
if src.AttributeTable().Len() <= int(v) {
3434
return fmt.Errorf("invalid attribute index %d", v)
3535
}
3636

0 commit comments

Comments
 (0)