FlameGraph: Fix bug for function names that conflict with JavaScript object prototype properties (#106338)
* grafana-flamegraph: Fix bug for function names that conflict with JavaScript object prototype properties The bug occurs in the flamegraph data transformation logic where function names from profiling data are used as object keys without proper prototype pollution protection. Fixes #106232 #101551 Co-authored-by: vinayteki95 <vinayteki95@users.noreply.github.com> * Fix top table calculations --------- Co-authored-by: vinayteki95 <vinayteki95@users.noreply.github.com> Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
This commit is contained in:
co-authored by
vinayteki95
Piotr Jamróz
parent
de28231f2f
commit
6156e9c2d8
@@ -75,6 +75,30 @@ describe('nestedSetToLevels', () => {
|
||||
expect(levels[0]).toEqual([n1]);
|
||||
expect(levels[1]).toEqual([n2, n3, n4]);
|
||||
});
|
||||
|
||||
it('handles strings that collide with inherited prototype method names', () => {
|
||||
const frame = createDataFrame({
|
||||
fields: [
|
||||
{ name: 'level', values: [0, 1, 1, 1] },
|
||||
{ name: 'value', values: [10, 5, 3, 1] },
|
||||
{ name: 'label', values: ['toString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf'], type: FieldType.string },
|
||||
{ name: 'self', values: [10, 5, 3, 1] },
|
||||
],
|
||||
});
|
||||
const [levels] = nestedSetToLevels(new FlameGraphDataContainer(frame, { collapsing: true }));
|
||||
|
||||
const n4: LevelItem = { itemIndexes: [3], start: 8, children: [], value: 1, level: 1 };
|
||||
const n3: LevelItem = { itemIndexes: [2], start: 5, children: [], value: 3, level: 1 };
|
||||
const n2: LevelItem = { itemIndexes: [1], start: 0, children: [], value: 5, level: 1 };
|
||||
const n1: LevelItem = { itemIndexes: [0], start: 0, children: [n2, n3, n4], value: 10, level: 0 };
|
||||
|
||||
n2.parents = [n1];
|
||||
n3.parents = [n1];
|
||||
n4.parents = [n1];
|
||||
|
||||
expect(levels[0]).toEqual([n1]);
|
||||
expect(levels[1]).toEqual([n2, n3, n4]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('FlameGraphDataContainer', () => {
|
||||
|
||||
@@ -46,7 +46,7 @@ export function nestedSetToLevels(
|
||||
let offset = 0;
|
||||
|
||||
let parent: LevelItem | undefined = undefined;
|
||||
const uniqueLabels: Record<string, LevelItem[]> = {};
|
||||
const uniqueLabels: Record<string, LevelItem[]> = Object.create(null);
|
||||
|
||||
for (let i = 0; i < container.data.length; i++) {
|
||||
const currentLevel = container.getLevel(i);
|
||||
|
||||
@@ -56,7 +56,7 @@ const FlameGraphTopTableContainer = memo(
|
||||
const table = useMemo(() => {
|
||||
// Group the data by label, we show only one row per label and sum the values
|
||||
// TODO: should be by filename + funcName + linenumber?
|
||||
let filteredTable: { [key: string]: TableData } = {};
|
||||
let filteredTable: { [key: string]: TableData } = Object.create(null);
|
||||
for (let i = 0; i < data.data.length; i++) {
|
||||
const value = data.getValue(i);
|
||||
const valueRight = data.getValueRight(i);
|
||||
|
||||
Reference in New Issue
Block a user