Re: [PATCH v4 1/6] perf dwarf-aux: Fix libdw segmentation fault in cu_walk_functions_at
From: Namhyung Kim
Date: Sun May 03 2026 - 19:34:00 EST
On Sun, May 03, 2026 at 10:10:27AM -0700, Ian Rogers wrote:
> A segmentation fault was observed in `libdw` when running `perf kmem`
> with `--page stat` on some workloads. The crash occurred deep inside
> `libdw` (specifically in `dwarf_child` and `dwarf_diename`) when
> processing DWARF information.
>
> The root cause was improper error handling of `dwarf_getfuncs` in
> `die_find_realfunc` and `die_find_tailfunc`.
>
> `dwarf_getfuncs` returns:
> - `0` on success (when all functions have been processed).
> - A positive offset if the callback aborts early (e.g., via
> `DWARF_CB_ABORT` when a match is found).
> - `-1` on error.
>
> The original code used `if (!dwarf_getfuncs(...)) return NULL;`. On
> error (`-1`), `!-1` evaluates to `0` (false), bypassing the error
> check. Execution then proceeded as if a match was found, returning
> uninitialized stack memory (`die_mem`) to the caller
> (`cu_walk_functions_at`). When `cu_walk_functions_at` passed this
> uninitialized memory to `libdw` via `dwarf_diename`, it caused a
> segmentation fault.
>
> Fix this by correcting the error check to `if (dwarf_getfuncs(...) <= 0)`.
>
> Fixes: e0d153c69040 ("perf-probe: Move dwarf library routines to dwarf-aux.{c, h}")
> Fixes: d4c537e6bf86 ("perf probe: Ignore tail calls to probed functions")
> Assisted-by: Gemini-CLI:Google Gemini 3
> Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
Acked-by: Namhyung Kim <namhyung@xxxxxxxxxx>
Thanks,
Namhyung
> ---
> tools/perf/util/dwarf-aux.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
> index 92db2fccc788..109a166a6d19 100644
> --- a/tools/perf/util/dwarf-aux.c
> +++ b/tools/perf/util/dwarf-aux.c
> @@ -171,7 +171,6 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
> }
>
> return ret;
> -
> }
>
> /**
> @@ -620,7 +619,7 @@ Dwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
> ad.addr = addr;
> ad.die_mem = die_mem;
> /* dwarf_getscopes can't find subprogram. */
> - if (!dwarf_getfuncs(cu_die, __die_search_func_tail_cb, &ad, 0))
> + if (dwarf_getfuncs(cu_die, __die_search_func_tail_cb, &ad, 0) <= 0)
> return NULL;
> else
> return die_mem;
> @@ -659,7 +658,7 @@ Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
> ad.addr = addr;
> ad.die_mem = die_mem;
> /* dwarf_getscopes can't find subprogram. */
> - if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
> + if (dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0) <= 0)
> return NULL;
> else
> return die_mem;
> --
> 2.54.0.545.g6539524ca2-goog
>