[PATCH 13/15] perf annotate-data: Bound the member nesting recursion

From: Arnaldo Carvalho de Melo

Date: Thu Sep 17 2026 - 12:33:42 EST


From: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>

Members are added recursively, and the same kind of broken DIE can make
a member's type point back at one of its own ancestors, recursing until
the stack is gone; nothing usable comes out of nesting members 8 deep
anyway, so stop there, marking the member as truncated (reported by the
JSON exporter added in a later series) and giving up on member types
that don't resolve.

Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
---
tools/perf/util/annotate-data.c | 32 ++++++++++++++++++++++++++------
tools/perf/util/annotate-data.h | 3 +++
2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
index 2ad6d012e069c522..c67bb6005e23c516 100644
--- a/tools/perf/util/annotate-data.c
+++ b/tools/perf/util/annotate-data.c
@@ -221,6 +221,13 @@ static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b)
return strcmp(a->self.type_name, b->self.type_name) < 0;
}

+/*
+ * Members are added recursively; bound the nesting so that a broken
+ * type that points back at one of its own ancestors doesn't recurse
+ * until the stack is gone.
+ */
+#define MAX_MEMBER_DEPTH 8
+
/* Recursively add new members for struct/union */
static int __add_member_cb(Dwarf_Die *die, void *arg)
{
@@ -235,6 +242,16 @@ static int __add_member_cb(Dwarf_Die *die, void *arg)
if (dwarf_tag(die) != DW_TAG_member)
return DIE_FIND_CB_SIBLING;

+ if (__die_get_real_type(die, &member_type) == NULL)
+ return DIE_FIND_CB_SIBLING;
+
+ if (dwarf_tag(&member_type) == DW_TAG_typedef) {
+ if (die_get_real_type(&member_type, &die_mem) == NULL)
+ return DIE_FIND_CB_SIBLING;
+ } else {
+ die_mem = member_type;
+ }
+
member = zalloc(sizeof(*member));
if (member == NULL)
return DIE_FIND_CB_END;
@@ -242,12 +259,6 @@ static int __add_member_cb(Dwarf_Die *die, void *arg)
strbuf_init(&sb, 32);
die_get_typename(die, &sb);

- __die_get_real_type(die, &member_type);
- if (dwarf_tag(&member_type) == DW_TAG_typedef)
- die_get_real_type(&member_type, &die_mem);
- else
- die_mem = member_type;
-
if (dwarf_aggregate_size(&die_mem, &size) < 0)
size = 0;

@@ -289,10 +300,19 @@ static int __add_member_cb(Dwarf_Die *die, void *arg)
}
member->size = size;
member->offset = loc + parent->offset;
+ member->depth = parent->depth + 1;
INIT_LIST_HEAD(&member->children);
list_add_tail(&member->node, &parent->children);

tag = dwarf_tag(&die_mem);
+ if (member->depth >= MAX_MEMBER_DEPTH) {
+ /* Reported by the JSON exporter so consumers can tell a truncated tree. */
+ member->truncated = true;
+ pr_debug_dtp("member nesting limit reached at %s\n",
+ member->type_name ?: "(unknown type)");
+ return DIE_FIND_CB_SIBLING;
+ }
+
switch (tag) {
case DW_TAG_structure_type:
case DW_TAG_union_type:
diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h
index ca2096a9ee62cbfe..cc576232f55b5fb0 100644
--- a/tools/perf/util/annotate-data.h
+++ b/tools/perf/util/annotate-data.h
@@ -57,6 +57,9 @@ struct annotated_member {
char *var_name;
int offset;
int size;
+ unsigned int depth;
+ /* Children not expanded because the nesting limit was reached */
+ bool truncated;
};

/**
--
2.55.0