[PATCH smatch 3/4] smatch: record free callsites for assigned struct members

Harshit Mogalapalli <[email protected]> Wed, 22 Apr 2026 07:32:18 -0700
Newsgroups org.kernel.vger.smatch
Message-ID <[email protected]>
Smatch tracks member freed-state flow but does not record which free
routine was used for each assigned struct member in function_type_info.

Add smatch_free_locations and wire it into the checker list and build.
The checker hooks definite and maybe-free paths, filters to real member
dereferences, extracts destination struct type/member, and stores the
free kind and free function name.

This records free-site provenance for teardown paths and makes member
free-site queries directly available to tooling.

Assisted-by: Codex:gpt-5.3-codex
Co-developed-by: Dan Carpenter <[email protected]>
Signed-off-by: Harshit Mogalapalli <[email protected]>
---
 Makefile                |  1 +
 check_list.h            |  1 +
 smatch_free_locations.c | 88 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 90 insertions(+)
 create mode 100644 smatch_free_locations.c

diff --git a/Makefile b/Makefile
index 1b8bd34ffd92..d5cfbd4b2593 100644
--- a/Makefile
+++ b/Makefile
@@ -285,6 +285,7 @@ SMATCH_OBJS += smatch_files.o
 SMATCH_OBJS += smatch_flow.o
 SMATCH_OBJS += smatch_fn_arg_link.o
 SMATCH_OBJS += smatch_free.o
+SMATCH_OBJS += smatch_free_locations.o
 SMATCH_OBJS += smatch_free_return_states.o
 SMATCH_OBJS += smatch_fresh_alloc.o
 SMATCH_OBJS += smatch_function_hooks.o
diff --git a/check_list.h b/check_list.h
index 330d43a12fb4..fb7883aa9f2f 100644
--- a/check_list.h
+++ b/check_list.h
@@ -87,6 +87,7 @@ CK(register_state_assigned)
 CK(register_points_to_container)
 CK(register_allocations)
 CK(register_allocations_locations)
+CK(register_free_locations)
 CK(register_units)
 CK(register_goto_tracker)
 CK(register_refcount)
diff --git a/smatch_free_locations.c b/smatch_free_locations.c
new file mode 100644
index 000000000000..03858be3f9a6
--- /dev/null
+++ b/smatch_free_locations.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2026 Oracle.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ */
+
+#include "smatch.h"
+#include "smatch_extra.h"
+
+static const char *get_free_fn_name(struct expression *expr)
+{
+	struct expression *call;
+	const char *fn_name;
+
+	call = get_assigned_call(expr);
+	if (!call)
+		return NULL;
+
+	fn_name = get_fn_name(call->fn);
+	return fn_name;
+}
+
+static void match_free_member(struct expression *expr, const char *name, struct symbol *sym, bool maybe)
+{
+	struct expression *arg;
+	struct symbol *type;
+	const char *fn_name;
+	char *type_str;
+	char *member;
+
+	if (__in_fake_assign)
+		return;
+
+	arg = gen_expression_from_name_sym(name, sym);
+	if (!arg)
+		return;
+	arg = strip_expr(arg);
+	if (!arg || arg->type != EXPR_DEREF || !arg->member)
+		return;
+
+	type = get_type(arg->deref);
+	if (!type || !type->ident)
+		return;
+
+	type_str = type_to_str(type);
+	if (!type_str)
+		return;
+
+	member = get_member_name_no_prefix(arg);
+	if (!member)
+		return;
+
+	fn_name = get_free_fn_name(expr);
+	if (!fn_name)
+		return;
+
+	if (maybe)
+		sql_insert_function_type_info(MAYBE_FREED, type_str, member, fn_name);
+	else
+		sql_insert_function_type_info(PARAM_FREED, type_str, member, fn_name);
+}
+
+static void match_free(struct expression *expr, const char *name, struct symbol *sym)
+{
+	match_free_member(expr, name, sym, false);
+}
+
+static void match_maybe_free(struct expression *expr, const char *name, struct symbol *sym)
+{
+	match_free_member(expr, name, sym, true);
+}
+
+void register_free_locations(int id)
+{
+	add_free_hook(&match_free);
+	add_maybe_free_hook(&match_maybe_free);
+}
-- 
2.47.3