Skip to content

libbpf-tools/ksnoop: Fix memory leaks#5442

Open
kknjh wants to merge 2 commits intoiovisor:masterfrom
kknjh:yf
Open

libbpf-tools/ksnoop: Fix memory leaks#5442
kknjh wants to merge 2 commits intoiovisor:masterfrom
kknjh:yf

Conversation

@kknjh
Copy link
Copy Markdown
Contributor

@kknjh kknjh commented Jan 8, 2026

cmd_info and cmd_trace return directly when the parse_traces function returns a negative value, but parse_traces may also fail at the parse_trace step. Therefore, we add the release logic here to address this scenario.

@Bojun-Seo
Copy link
Copy Markdown
Contributor

Great catch!

Applying this patch as-is might be a good approach, but the issue seems to stem from how the code is structured, making such problems more likely to occur. Instead of directly applying this patch, what if we restructure the function's role? That way, the overall structure would be better, and it would be easier to maintain.

I suggest modifying the parse_traces function so that it only retains its core functionality of parsing traces, while the memory allocation for this function is handled by the user—specifically, by the cmd_info and cmd_trace functions. By doing this, the functions responsible for allocating memory would also handle its deallocation, reducing the chance of developer errors and making maintenance easier.

What do you think?

cmd_info and cmd_trace return directly when the parse_traces function
returns a negative value, but parse_traces may also fail at the parse_trace step.
Avoid such issues by restructuring the relevant functions.

Signed-off-by: Feng Yang <yangfeng@kylinos.cn>
@kknjh
Copy link
Copy Markdown
Contributor Author

kknjh commented Jan 9, 2026

Great catch!

Applying this patch as-is might be a good approach, but the issue seems to stem from how the code is structured, making such problems more likely to occur. Instead of directly applying this patch, what if we restructure the function's role? That way, the overall structure would be better, and it would be easier to maintain.

I suggest modifying the parse_traces function so that it only retains its core functionality of parsing traces, while the memory allocation for this function is handled by the user—specifically, by the cmd_info and cmd_trace functions. By doing this, the functions responsible for allocating memory would also handle its deallocation, reducing the chance of developer errors and making maintenance easier.

What do you think?

Modified, thank you.

@Bojun-Seo
Copy link
Copy Markdown
Contributor

LGTM!


nr_traces = parse_traces(argc, argv, traces);
if (nr_traces < 0) {
free(traces);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dynamically allocated fields within each trace structure are not being properly cleaned up?
In parse_trace() at line 557:
trace->dump = btf_dump__new(trace->btf, trace_printf, NULL, NULL);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another great catch!
While it is still a memory leak like the original one, I think it would be better to handle this fix in a separate patch or PR.
Since it is happening at a separate location in the code.

Copy link
Copy Markdown
Contributor

@Bojun-Seo Bojun-Seo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, this patch series fixes three memory leaks and improves the overall resource management structure of ksnoop.

static void free_traces(struct trace *traces)
{
btf_dump__free(traces->dump);
btf__free(traces->btf);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! This is another good one.

The traces->btf is allocated via btf__load_vmlinux_btf(), which returns a struct btf * that the caller is responsible for freeing with btf__free().

Reference
https://docs.ebpf.io/ebpf-library/libbpf/userspace/btf__load_vmlinux_btf/

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to fix memory leaks in ksnoop by ensuring trace allocations are released when argument parsing fails (especially when parse_trace() fails mid-way), and by centralizing trace allocation/free logic for cmd_info and cmd_trace.

Changes:

  • Refactors parse_traces() to only parse into a caller-allocated trace array.
  • Adds alloc_traces() and free_traces() helpers and updates cmd_info/cmd_trace to use them on error paths.
  • Adjusts cmd_trace to use a common cleanup: path for better resource release.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +671 to +675
static void free_traces(struct trace *traces)
{
btf_dump__free(traces->dump);
btf__free(traces->btf);
free(traces);
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free_traces() only frees btf/dump for traces[0] (via traces->dump / traces->btf). Each parsed trace allocates its own btf_dump (and may load a module BTF), so this will still leak resources for traces[1..] and won’t fully fix the failure path when parse_trace() fails after some traces were already parsed. Consider passing the trace count into free_traces() and iterating over all entries, freeing each trace[i].dump and any per-trace-owned BTF before freeing the array.

Copilot uses AI. Check for mistakes.
Comment on lines +673 to +674
btf_dump__free(traces->dump);
btf__free(traces->btf);
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

free_traces() unconditionally calls btf__free(traces->btf), but trace->btf can be the shared global vmlinux_btf returned by get_btf(NULL). Freeing that here can leave vmlinux_btf dangling (and if free_traces is later updated to loop, it risks double-free when multiple traces use vmlinux_btf). Track ownership explicitly (e.g., only btf__free() module BTF instances, and free vmlinux_btf once at process shutdown if desired).

Suggested change
btf_dump__free(traces->dump);
btf__free(traces->btf);
if (!traces)
return;
if (traces->dump)
btf_dump__free(traces->dump);
if (traces->btf && traces->btf != vmlinux_btf)
btf__free(traces->btf);

Copilot uses AI. Check for mistakes.
Add a dedicated deallocation function to include the release of data within the structure

Signed-off-by: Feng Yang <yangfeng@kylinos.cn>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants