linux-trace-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe
@ 2025-01-07 11:50 Masami Hiramatsu (Google)
  2025-01-07 11:50 ` [PATCH v3 1/5] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-07 11:50 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

Hi,

Here is the 3rd version of the series to fix and cleanup probe events in
ftrace with __free(). I resend this without dynevent and argv_free
parts because it has been sent by Steve[1]. And I updated the version
tag.

In this version, I fixed some issues[5/7] and update DEFINE_FREE() tag
name to specify freeing function name so that reader can understand it
easily[2/7].
Also, I added trace_fprobe cleanup with free[7/7].

Thanks,

---

Masami Hiramatsu (Google) (5):
      tracing/kprobes: Fix to free objects when failed to copy a symbol
      tracing: Use __free() in trace_probe for cleanup
      tracing: Use __free() for kprobe events to cleanup
      tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos
      tracing: Adopt __free() and guard() for trace_fprobe.c


 kernel/trace/trace_fprobe.c |  129 +++++++++++++++++++-----------------------
 kernel/trace/trace_kprobe.c |  133 ++++++++++++++++++++++---------------------
 kernel/trace/trace_probe.c  |   52 ++++++-----------
 3 files changed, 145 insertions(+), 169 deletions(-)

--
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 1/5] tracing/kprobes: Fix to free objects when failed to copy a symbol
  2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
@ 2025-01-07 11:50 ` Masami Hiramatsu (Google)
  2025-01-07 11:50 ` [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-07 11:50 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

In __trace_kprobe_create(), if something fails it must goto error block
to free objects. But when strdup() a symbol, it returns without that.
Fix it to goto the error block to free objects correctly.

Fixes: 6212dd29683e ("tracing/kprobes: Use dyn_event framework for kprobe events")
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 263fac44d3ca..fb9d4dffa66e 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -940,8 +940,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		}
 		/* a symbol specified */
 		symbol = kstrdup(argv[1], GFP_KERNEL);
-		if (!symbol)
-			return -ENOMEM;
+		if (!symbol) {
+			ret = -ENOMEM;
+			goto error;
+		}
 
 		tmp = strchr(symbol, '%');
 		if (tmp) {


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup
  2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
  2025-01-07 11:50 ` [PATCH v3 1/5] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
@ 2025-01-07 11:50 ` Masami Hiramatsu (Google)
  2025-01-07 15:36   ` Steven Rostedt
  2025-01-07 11:50 ` [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-07 11:50 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Use __free() in trace_probe to cleanup some gotos.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_probe.c |   52 +++++++++++++++-----------------------------
 1 file changed, 18 insertions(+), 34 deletions(-)

diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 16a5e368e7b7..bf6a7b81ae95 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -1409,7 +1409,7 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 					   struct traceprobe_parse_context *ctx)
 {
 	struct fetch_insn *code, *tmp = NULL;
-	char *type, *arg;
+	char *type, *arg __free(kfree) = NULL;
 	int ret, len;
 
 	len = strlen(argv);
@@ -1426,22 +1426,16 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 		return -ENOMEM;
 
 	parg->comm = kstrdup(arg, GFP_KERNEL);
-	if (!parg->comm) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!parg->comm)
+		return -ENOMEM;
 
 	type = parse_probe_arg_type(arg, parg, ctx);
-	if (IS_ERR(type)) {
-		ret = PTR_ERR(type);
-		goto out;
-	}
+	if (IS_ERR(type))
+		return PTR_ERR(type);
 
 	code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);
-	if (!code) {
-		ret = -ENOMEM;
-		goto out;
-	}
+	if (!code)
+		return -ENOMEM;
 	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
 
 	ctx->last_type = NULL;
@@ -1497,8 +1491,6 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
 				kfree(code->data);
 	}
 	kfree(tmp);
-out:
-	kfree(arg);
 
 	return ret;
 }
@@ -1668,7 +1660,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 {
 	const struct btf_param *params = NULL;
 	int i, j, n, used, ret, args_idx = -1;
-	const char **new_argv = NULL;
+	const char **new_argv __free(kfree) = NULL;
 
 	ret = argv_has_var_arg(argc, argv, &args_idx, ctx);
 	if (ret < 0)
@@ -1707,7 +1699,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 				ret = sprint_nth_btf_arg(n, "", buf + used,
 							 bufsize - used, ctx);
 				if (ret < 0)
-					goto error;
+					return ERR_PTR(ret);
 
 				new_argv[j++] = buf + used;
 				used += ret + 1;
@@ -1721,25 +1713,20 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 			n = simple_strtoul(argv[i] + 4, &type, 10);
 			if (type && !(*type == ':' || *type == '\0')) {
 				trace_probe_log_err(0, BAD_VAR);
-				ret = -ENOENT;
-				goto error;
+				return ERR_PTR(-ENOENT);
 			}
 			/* Note: $argN starts from $arg1 */
 			ret = sprint_nth_btf_arg(n - 1, type, buf + used,
 						 bufsize - used, ctx);
 			if (ret < 0)
-				goto error;
+				return ERR_PTR(ret);
 			new_argv[j++] = buf + used;
 			used += ret + 1;
 		} else
 			new_argv[j++] = argv[i];
 	}
 
-	return new_argv;
-
-error:
-	kfree(new_argv);
-	return ERR_PTR(ret);
+	return_ptr(new_argv);
 }
 
 /* @buf: *buf must be equal to NULL. Caller must to free *buf */
@@ -1747,14 +1734,14 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
 {
 	int i, used, ret;
 	const int bufsize = MAX_DENTRY_ARGS_LEN;
-	char *tmpbuf = NULL;
+	char *tmpbuf __free(kfree) = NULL;
 
 	if (*buf)
 		return -EINVAL;
 
 	used = 0;
 	for (i = 0; i < argc; i++) {
-		char *tmp;
+		char *tmp __free(kfree) = NULL;
 		char *equal;
 		size_t arg_len;
 
@@ -1769,7 +1756,7 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
 
 		tmp = kstrdup(argv[i], GFP_KERNEL);
 		if (!tmp)
-			goto nomem;
+			return -ENOMEM;
 
 		equal = strchr(tmp, '=');
 		if (equal)
@@ -1790,18 +1777,15 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
 				       offsetof(struct file, f_path.dentry),
 				       equal ? equal + 1 : tmp);
 
-		kfree(tmp);
+		kfree(no_free_ptr(tmp));
 		if (ret >= bufsize - used)
-			goto nomem;
+			return -ENOMEM;
 		argv[i] = tmpbuf + used;
 		used += ret + 1;
 	}
 
-	*buf = tmpbuf;
+	*buf = no_free_ptr(tmpbuf);
 	return 0;
-nomem:
-	kfree(tmpbuf);
-	return -ENOMEM;
 }
 
 void traceprobe_finish_parse(struct traceprobe_parse_context *ctx)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup
  2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
  2025-01-07 11:50 ` [PATCH v3 1/5] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
  2025-01-07 11:50 ` [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
@ 2025-01-07 11:50 ` Masami Hiramatsu (Google)
  2025-01-07 15:42   ` Steven Rostedt
  2025-01-07 11:50 ` [PATCH v3 4/5] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos Masami Hiramatsu (Google)
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-07 11:50 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Use __free() in trace_kprobe.c to cleanup code.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v3:
  - Rename to __free(free_trace_kprobe) to clarify what function will be called.
  - Add !IS_ERR_OR_NULL() check because alloc_trace_kprobe() returns an error code.
  - Prevent freeing 'tk' in create_local_trace_kprobe() when succeeded to register.
 Changes in v2:
  - Instead of using no_free_ptr(), just assign NULL to the registered pointer.
---
 kernel/trace/trace_kprobe.c |   63 +++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 32 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index fb9d4dffa66e..2d8b5ef47e96 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -8,6 +8,7 @@
 #define pr_fmt(fmt)	"trace_kprobe: " fmt
 
 #include <linux/bpf-cgroup.h>
+#include <linux/cleanup.h>
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
@@ -257,6 +258,9 @@ static void free_trace_kprobe(struct trace_kprobe *tk)
 	}
 }
 
+DEFINE_FREE(free_trace_kprobe, struct trace_kprobe *,
+	if (!IS_ERR_OR_NULL(_T)) free_trace_kprobe(_T))
+
 /*
  * Allocate new trace_probe and initialize it (including kprobes).
  */
@@ -268,7 +272,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 					     int maxactive,
 					     int nargs, bool is_return)
 {
-	struct trace_kprobe *tk;
+	struct trace_kprobe *tk __free(free_trace_kprobe) = NULL;
 	int ret = -ENOMEM;
 
 	tk = kzalloc(struct_size(tk, tp.args, nargs), GFP_KERNEL);
@@ -277,12 +281,12 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 
 	tk->nhit = alloc_percpu(unsigned long);
 	if (!tk->nhit)
-		goto error;
+		return ERR_PTR(ret);
 
 	if (symbol) {
 		tk->symbol = kstrdup(symbol, GFP_KERNEL);
 		if (!tk->symbol)
-			goto error;
+			return ERR_PTR(ret);
 		tk->rp.kp.symbol_name = tk->symbol;
 		tk->rp.kp.offset = offs;
 	} else
@@ -299,13 +303,10 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
 
 	ret = trace_probe_init(&tk->tp, event, group, false, nargs);
 	if (ret < 0)
-		goto error;
+		return ERR_PTR(ret);
 
 	dyn_event_init(&tk->devent, &trace_kprobe_ops);
-	return tk;
-error:
-	free_trace_kprobe(tk);
-	return ERR_PTR(ret);
+	return_ptr(tk);
 }
 
 static struct trace_kprobe *find_trace_kprobe(const char *event,
@@ -866,11 +867,12 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	 * Type of args:
 	 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 	 */
-	struct trace_kprobe *tk = NULL;
+	struct trace_kprobe *tk __free(free_trace_kprobe) = NULL;
 	int i, len, new_argc = 0, ret = 0;
 	bool is_return = false;
-	char *symbol = NULL, *tmp = NULL;
-	const char **new_argv = NULL;
+	char *symbol __free(kfree) = NULL;
+	char *tmp = NULL;
+	const char **new_argv __free(kfree) = NULL;
 	const char *event = NULL, *group = KPROBE_EVENT_SYSTEM;
 	enum probe_print_type ptype;
 	int maxactive = 0;
@@ -879,7 +881,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	char buf[MAX_EVENT_NAME_LEN];
 	char gbuf[MAX_EVENT_NAME_LEN];
 	char abuf[MAX_BTF_ARGS_LEN];
-	char *dbuf = NULL;
+	char *dbuf __free(kfree) = NULL;
 	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
 
 	switch (argv[0][0]) {
@@ -936,7 +938,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		/* Check whether uprobe event specified */
 		if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
 			ret = -ECANCELED;
-			goto error;
+			goto out;
 		}
 		/* a symbol specified */
 		symbol = kstrdup(argv[1], GFP_KERNEL);
@@ -1040,7 +1042,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ctx.offset = 0;
 		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
 		if (ret)
-			goto error;	/* This can be -ENOMEM */
+			goto out;	/* This can be -ENOMEM */
 	}
 	/* entry handler for kretprobe */
 	if (is_return && tk->tp.entry_arg) {
@@ -1051,7 +1053,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
 	ret = traceprobe_set_print_fmt(&tk->tp, ptype);
 	if (ret < 0)
-		goto error;
+		goto out;
 
 	ret = register_trace_kprobe(tk);
 	if (ret) {
@@ -1062,21 +1064,20 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
 		else if (ret != -ENOMEM && ret != -EEXIST)
 			trace_probe_log_err(0, FAIL_REG_PROBE);
-		goto error;
-	}
+	} else
+		/*
+		 * Here, 'tk' has been registered to the list successfully,
+		 * so we don't need to free it.
+		 */
+		tk = NULL;
 
 out:
 	traceprobe_finish_parse(&ctx);
 	trace_probe_log_clear();
-	kfree(new_argv);
-	kfree(symbol);
-	kfree(dbuf);
 	return ret;
 
 parse_error:
 	ret = -EINVAL;
-error:
-	free_trace_kprobe(tk);
 	goto out;
 }
 
@@ -1898,7 +1899,8 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 			  bool is_return)
 {
 	enum probe_print_type ptype;
-	struct trace_kprobe *tk;
+	struct trace_kprobe *tk __free(free_trace_kprobe) = NULL;
+	struct trace_probe *tp;
 	int ret;
 	char *event;
 
@@ -1929,19 +1931,16 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
 
 	ptype = trace_kprobe_is_return(tk) ?
 		PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
-	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0) {
-		ret = -ENOMEM;
-		goto error;
-	}
+	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0)
+		return ERR_PTR(-ENOMEM);
 
 	ret = __register_trace_kprobe(tk);
 	if (ret < 0)
-		goto error;
+		return ERR_PTR(ret);
 
-	return trace_probe_event_call(&tk->tp);
-error:
-	free_trace_kprobe(tk);
-	return ERR_PTR(ret);
+	tp = &tk->tp;
+	tk = NULL;	/* 'tk' is registered successfully, so do not free. */
+	return trace_probe_event_call(tp);
 }
 
 void destroy_local_trace_kprobe(struct trace_event_call *event_call)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 4/5] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos
  2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
                   ` (2 preceding siblings ...)
  2025-01-07 11:50 ` [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
@ 2025-01-07 11:50 ` Masami Hiramatsu (Google)
  2025-01-07 11:50 ` [PATCH v3 5/5] tracing: Adopt __free() and guard() for trace_fprobe.c Masami Hiramatsu (Google)
  2025-01-07 11:53 ` [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu
  5 siblings, 0 replies; 13+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-07 11:50 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Simplify __trace_kprobe_create() by removing gotos.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_kprobe.c |   82 ++++++++++++++++++++++---------------------
 1 file changed, 41 insertions(+), 41 deletions(-)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 2d8b5ef47e96..f487473cf255 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -841,7 +841,8 @@ static int validate_probe_symbol(char *symbol)
 static int trace_kprobe_entry_handler(struct kretprobe_instance *ri,
 				      struct pt_regs *regs);
 
-static int __trace_kprobe_create(int argc, const char *argv[])
+static int ___trace_kprobe_create(int argc, const char *argv[],
+				  struct traceprobe_parse_context *ctx)
 {
 	/*
 	 * Argument syntax:
@@ -882,7 +883,6 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	char gbuf[MAX_EVENT_NAME_LEN];
 	char abuf[MAX_BTF_ARGS_LEN];
 	char *dbuf __free(kfree) = NULL;
-	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
 
 	switch (argv[0][0]) {
 	case 'r':
@@ -896,8 +896,6 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	if (argc < 2)
 		return -ECANCELED;
 
-	trace_probe_log_init("trace_kprobe", argc, argv);
-
 	event = strchr(&argv[0][1], ':');
 	if (event)
 		event++;
@@ -905,7 +903,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	if (isdigit(argv[0][1])) {
 		if (!is_return) {
 			trace_probe_log_err(1, BAD_MAXACT_TYPE);
-			goto parse_error;
+			return -EINVAL;
 		}
 		if (event)
 			len = event - &argv[0][1] - 1;
@@ -913,21 +911,21 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 			len = strlen(&argv[0][1]);
 		if (len > MAX_EVENT_NAME_LEN - 1) {
 			trace_probe_log_err(1, BAD_MAXACT);
-			goto parse_error;
+			return -EINVAL;
 		}
 		memcpy(buf, &argv[0][1], len);
 		buf[len] = '\0';
 		ret = kstrtouint(buf, 0, &maxactive);
 		if (ret || !maxactive) {
 			trace_probe_log_err(1, BAD_MAXACT);
-			goto parse_error;
+			return -EINVAL;
 		}
 		/* kretprobes instances are iterated over via a list. The
 		 * maximum should stay reasonable.
 		 */
 		if (maxactive > KRETPROBE_MAXACTIVE_MAX) {
 			trace_probe_log_err(1, MAXACT_TOO_BIG);
-			goto parse_error;
+			return -EINVAL;
 		}
 	}
 
@@ -936,16 +934,13 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) {
 		trace_probe_log_set_index(1);
 		/* Check whether uprobe event specified */
-		if (strchr(argv[1], '/') && strchr(argv[1], ':')) {
-			ret = -ECANCELED;
-			goto out;
-		}
+		if (strchr(argv[1], '/') && strchr(argv[1], ':'))
+			return -ECANCELED;
+
 		/* a symbol specified */
 		symbol = kstrdup(argv[1], GFP_KERNEL);
-		if (!symbol) {
-			ret = -ENOMEM;
-			goto error;
-		}
+		if (!symbol)
+			return -ENOMEM;
 
 		tmp = strchr(symbol, '%');
 		if (tmp) {
@@ -954,7 +949,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 				is_return = true;
 			} else {
 				trace_probe_log_err(tmp - symbol, BAD_ADDR_SUFFIX);
-				goto parse_error;
+				return -EINVAL;
 			}
 		}
 
@@ -962,7 +957,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ret = traceprobe_split_symbol_offset(symbol, &offset);
 		if (ret || offset < 0 || offset > UINT_MAX) {
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
-			goto parse_error;
+			return -EINVAL;
 		}
 		ret = validate_probe_symbol(symbol);
 		if (ret) {
@@ -970,17 +965,17 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 				trace_probe_log_err(0, NON_UNIQ_SYMBOL);
 			else
 				trace_probe_log_err(0, BAD_PROBE_ADDR);
-			goto parse_error;
+			return -EINVAL;
 		}
 		if (is_return)
-			ctx.flags |= TPARG_FL_RETURN;
+			ctx->flags |= TPARG_FL_RETURN;
 		ret = kprobe_on_func_entry(NULL, symbol, offset);
 		if (ret == 0 && !is_return)
-			ctx.flags |= TPARG_FL_FENTRY;
+			ctx->flags |= TPARG_FL_FENTRY;
 		/* Defer the ENOENT case until register kprobe */
 		if (ret == -EINVAL && is_return) {
 			trace_probe_log_err(0, BAD_RETPROBE);
-			goto parse_error;
+			return -EINVAL;
 		}
 	}
 
@@ -989,7 +984,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ret = traceprobe_parse_event_name(&event, &group, gbuf,
 						  event - argv[0]);
 		if (ret)
-			goto parse_error;
+			return ret;
 	}
 
 	if (!event) {
@@ -1005,26 +1000,24 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	}
 
 	argc -= 2; argv += 2;
-	ctx.funcname = symbol;
+	ctx->funcname = symbol;
 	new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
-					       abuf, MAX_BTF_ARGS_LEN, &ctx);
+					       abuf, MAX_BTF_ARGS_LEN, ctx);
 	if (IS_ERR(new_argv)) {
 		ret = PTR_ERR(new_argv);
 		new_argv = NULL;
-		goto out;
+		return ret;
 	}
 	if (new_argv) {
 		argc = new_argc;
 		argv = new_argv;
 	}
-	if (argc > MAX_TRACE_ARGS) {
-		ret = -E2BIG;
-		goto out;
-	}
+	if (argc > MAX_TRACE_ARGS)
+		return -E2BIG;
 
 	ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
 	if (ret)
-		goto out;
+		return ret;
 
 	/* setup a probe */
 	tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
@@ -1033,16 +1026,16 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		ret = PTR_ERR(tk);
 		/* This must return -ENOMEM, else there is a bug */
 		WARN_ON_ONCE(ret != -ENOMEM);
-		goto out;	/* We know tk is not allocated */
+		return ret;	/* We know tk is not allocated */
 	}
 
 	/* parse arguments */
 	for (i = 0; i < argc; i++) {
 		trace_probe_log_set_index(i + 2);
-		ctx.offset = 0;
-		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
+		ctx->offset = 0;
+		ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], ctx);
 		if (ret)
-			goto out;	/* This can be -ENOMEM */
+			return ret;	/* This can be -ENOMEM */
 	}
 	/* entry handler for kretprobe */
 	if (is_return && tk->tp.entry_arg) {
@@ -1053,7 +1046,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 	ptype = is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
 	ret = traceprobe_set_print_fmt(&tk->tp, ptype);
 	if (ret < 0)
-		goto out;
+		return ret;
 
 	ret = register_trace_kprobe(tk);
 	if (ret) {
@@ -1071,14 +1064,21 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 		 */
 		tk = NULL;
 
-out:
+	return ret;
+}
+
+static int __trace_kprobe_create(int argc, const char *argv[])
+{
+	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
+	int ret;
+
+	trace_probe_log_init("trace_kprobe", argc, argv);
+
+	ret = ___trace_kprobe_create(argc, argv, &ctx);
+
 	traceprobe_finish_parse(&ctx);
 	trace_probe_log_clear();
 	return ret;
-
-parse_error:
-	ret = -EINVAL;
-	goto out;
 }
 
 static int trace_kprobe_create(const char *raw_command)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 5/5] tracing: Adopt __free() and guard() for trace_fprobe.c
  2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
                   ` (3 preceding siblings ...)
  2025-01-07 11:50 ` [PATCH v3 4/5] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos Masami Hiramatsu (Google)
@ 2025-01-07 11:50 ` Masami Hiramatsu (Google)
  2025-01-07 11:53 ` [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu
  5 siblings, 0 replies; 13+ messages in thread
From: Masami Hiramatsu (Google) @ 2025-01-07 11:50 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra
  Cc: Anil S Keshavamurthy, Masami Hiramatsu, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Adopt __free() and guard() for trace_fprobe.c to remove gotos.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace_fprobe.c |  129 ++++++++++++++++++++-----------------------
 1 file changed, 60 insertions(+), 69 deletions(-)

diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
index c62d1629cffe..6d339c426b5d 100644
--- a/kernel/trace/trace_fprobe.c
+++ b/kernel/trace/trace_fprobe.c
@@ -379,6 +379,9 @@ static void free_trace_fprobe(struct trace_fprobe *tf)
 	}
 }
 
+/* Since alloc_trace_fprobe() can return error, check the pointer is ERR too. */
+DEFINE_FREE(trace_fprobe, struct trace_fprobe *, if (!IS_ERR_OR_NULL(_T)) free_trace_fprobe(_T))
+
 /*
  * Allocate new trace_probe and initialize it (including fprobe).
  */
@@ -390,7 +393,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
 					       int maxactive,
 					       int nargs, bool is_return)
 {
-	struct trace_fprobe *tf;
+	struct trace_fprobe *tf __free(trace_fprobe) = NULL;
 	int ret = -ENOMEM;
 
 	tf = kzalloc(struct_size(tf, tp.args, nargs), GFP_KERNEL);
@@ -399,7 +402,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
 
 	tf->symbol = kstrdup(symbol, GFP_KERNEL);
 	if (!tf->symbol)
-		goto error;
+		return ERR_PTR(-ENOMEM);
 
 	if (is_return)
 		tf->fp.exit_handler = fexit_dispatcher;
@@ -412,13 +415,10 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
 
 	ret = trace_probe_init(&tf->tp, event, group, false, nargs);
 	if (ret < 0)
-		goto error;
+		return ERR_PTR(ret);
 
 	dyn_event_init(&tf->devent, &trace_fprobe_ops);
-	return tf;
-error:
-	free_trace_fprobe(tf);
-	return ERR_PTR(ret);
+	return_ptr(tf);
 }
 
 static struct trace_fprobe *find_trace_fprobe(const char *event,
@@ -845,14 +845,12 @@ static int register_trace_fprobe(struct trace_fprobe *tf)
 	struct trace_fprobe *old_tf;
 	int ret;
 
-	mutex_lock(&event_mutex);
+	guard(mutex)(&event_mutex);
 
 	old_tf = find_trace_fprobe(trace_probe_name(&tf->tp),
 				   trace_probe_group_name(&tf->tp));
-	if (old_tf) {
-		ret = append_trace_fprobe(tf, old_tf);
-		goto end;
-	}
+	if (old_tf)
+		return append_trace_fprobe(tf, old_tf);
 
 	/* Register new event */
 	ret = register_fprobe_event(tf);
@@ -862,7 +860,7 @@ static int register_trace_fprobe(struct trace_fprobe *tf)
 			trace_probe_log_err(0, EVENT_EXIST);
 		} else
 			pr_warn("Failed to register probe event(%d)\n", ret);
-		goto end;
+		return ret;
 	}
 
 	/* Register fprobe */
@@ -872,8 +870,6 @@ static int register_trace_fprobe(struct trace_fprobe *tf)
 	else
 		dyn_event_add(&tf->devent, trace_probe_event_call(&tf->tp));
 
-end:
-	mutex_unlock(&event_mutex);
 	return ret;
 }
 
@@ -1034,7 +1030,10 @@ static int parse_symbol_and_return(int argc, const char *argv[],
 	return 0;
 }
 
-static int __trace_fprobe_create(int argc, const char *argv[])
+DEFINE_FREE(module_put, struct module *, if (_T) module_put(_T))
+
+static int ___trace_fprobe_create(int argc, const char *argv[],
+				  struct traceprobe_parse_context *ctx)
 {
 	/*
 	 * Argument syntax:
@@ -1060,24 +1059,21 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 	 * Type of args:
 	 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 	 */
-	struct trace_fprobe *tf = NULL;
+	struct trace_fprobe *tf __free(trace_fprobe) = NULL;
 	int i, len, new_argc = 0, ret = 0;
 	bool is_return = false;
-	char *symbol = NULL;
+	char *symbol __free(kfree) = NULL;
 	const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
-	const char **new_argv = NULL;
+	const char **new_argv __free(kfree) = NULL;
 	int maxactive = 0;
 	char buf[MAX_EVENT_NAME_LEN];
 	char gbuf[MAX_EVENT_NAME_LEN];
 	char sbuf[KSYM_NAME_LEN];
 	char abuf[MAX_BTF_ARGS_LEN];
-	char *dbuf = NULL;
+	char *dbuf __free(kfree) = NULL;
 	bool is_tracepoint = false;
-	struct module *tp_mod = NULL;
+	struct module *tp_mod __free(module_put) = NULL;
 	struct tracepoint *tpoint = NULL;
-	struct traceprobe_parse_context ctx = {
-		.flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE,
-	};
 
 	if ((argv[0][0] != 'f' && argv[0][0] != 't') || argc < 2)
 		return -ECANCELED;
@@ -1087,8 +1083,6 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 		group = TRACEPOINT_EVENT_SYSTEM;
 	}
 
-	trace_probe_log_init("trace_fprobe", argc, argv);
-
 	event = strchr(&argv[0][1], ':');
 	if (event)
 		event++;
@@ -1100,21 +1094,21 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 			len = strlen(&argv[0][1]);
 		if (len > MAX_EVENT_NAME_LEN - 1) {
 			trace_probe_log_err(1, BAD_MAXACT);
-			goto parse_error;
+			return -EINVAL;
 		}
 		memcpy(buf, &argv[0][1], len);
 		buf[len] = '\0';
 		ret = kstrtouint(buf, 0, &maxactive);
 		if (ret || !maxactive) {
 			trace_probe_log_err(1, BAD_MAXACT);
-			goto parse_error;
+			return -EINVAL;
 		}
 		/* fprobe rethook instances are iterated over via a list. The
 		 * maximum should stay reasonable.
 		 */
 		if (maxactive > RETHOOK_MAXACTIVE_MAX) {
 			trace_probe_log_err(1, MAXACT_TOO_BIG);
-			goto parse_error;
+			return -EINVAL;
 		}
 	}
 
@@ -1123,12 +1117,12 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 	/* a symbol(or tracepoint) must be specified */
 	ret = parse_symbol_and_return(argc, argv, &symbol, &is_return, is_tracepoint);
 	if (ret < 0)
-		goto parse_error;
+		return -EINVAL;
 
 	if (!is_return && maxactive) {
 		trace_probe_log_set_index(0);
 		trace_probe_log_err(1, BAD_MAXACT_TYPE);
-		goto parse_error;
+		return -EINVAL;
 	}
 
 	trace_probe_log_set_index(0);
@@ -1136,7 +1130,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 		ret = traceprobe_parse_event_name(&event, &group, gbuf,
 						  event - argv[0]);
 		if (ret)
-			goto parse_error;
+			return -EINVAL;
 	}
 
 	if (!event) {
@@ -1152,49 +1146,44 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 	}
 
 	if (is_return)
-		ctx.flags |= TPARG_FL_RETURN;
+		ctx->flags |= TPARG_FL_RETURN;
 	else
-		ctx.flags |= TPARG_FL_FENTRY;
+		ctx->flags |= TPARG_FL_FENTRY;
 
 	if (is_tracepoint) {
-		ctx.flags |= TPARG_FL_TPOINT;
+		ctx->flags |= TPARG_FL_TPOINT;
 		tpoint = find_tracepoint(symbol, &tp_mod);
 		if (tpoint) {
-			ctx.funcname = kallsyms_lookup(
+			ctx->funcname = kallsyms_lookup(
 				(unsigned long)tpoint->probestub,
 				NULL, NULL, NULL, sbuf);
 		} else if (IS_ENABLED(CONFIG_MODULES)) {
 				/* This *may* be loaded afterwards */
 				tpoint = TRACEPOINT_STUB;
-				ctx.funcname = symbol;
+				ctx->funcname = symbol;
 		} else {
 			trace_probe_log_set_index(1);
 			trace_probe_log_err(0, NO_TRACEPOINT);
-			goto parse_error;
+			return -EINVAL;
 		}
 	} else
-		ctx.funcname = symbol;
+		ctx->funcname = symbol;
 
 	argc -= 2; argv += 2;
 	new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
-					       abuf, MAX_BTF_ARGS_LEN, &ctx);
-	if (IS_ERR(new_argv)) {
-		ret = PTR_ERR(new_argv);
-		new_argv = NULL;
-		goto out;
-	}
+					       abuf, MAX_BTF_ARGS_LEN, ctx);
+	if (IS_ERR(new_argv))
+		return PTR_ERR(new_argv);
 	if (new_argv) {
 		argc = new_argc;
 		argv = new_argv;
 	}
-	if (argc > MAX_TRACE_ARGS) {
-		ret = -E2BIG;
-		goto out;
-	}
+	if (argc > MAX_TRACE_ARGS)
+		return -E2BIG;
 
 	ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
 	if (ret)
-		goto out;
+		return ret;
 
 	/* setup a probe */
 	tf = alloc_trace_fprobe(group, event, symbol, tpoint, tp_mod,
@@ -1203,16 +1192,16 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 		ret = PTR_ERR(tf);
 		/* This must return -ENOMEM, else there is a bug */
 		WARN_ON_ONCE(ret != -ENOMEM);
-		goto out;	/* We know tf is not allocated */
+		return ret;
 	}
 
 	/* parse arguments */
 	for (i = 0; i < argc; i++) {
 		trace_probe_log_set_index(i + 2);
-		ctx.offset = 0;
-		ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], &ctx);
+		ctx->offset = 0;
+		ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], ctx);
 		if (ret)
-			goto error;	/* This can be -ENOMEM */
+			return ret;	/* This can be -ENOMEM */
 	}
 
 	if (is_return && tf->tp.entry_arg) {
@@ -1223,7 +1212,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 	ret = traceprobe_set_print_fmt(&tf->tp,
 			is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL);
 	if (ret < 0)
-		goto error;
+		return ret;
 
 	ret = register_trace_fprobe(tf);
 	if (ret) {
@@ -1234,24 +1223,26 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 			trace_probe_log_err(0, BAD_PROBE_ADDR);
 		else if (ret != -ENOMEM && ret != -EEXIST)
 			trace_probe_log_err(0, FAIL_REG_PROBE);
-		goto error;
-	}
+		ret = -EINVAL;
+	} else
+		/* 'tf' is successfully registered. To avoid freeing, assign NULL. */
+		tf = NULL;
 
-out:
-	if (tp_mod)
-		module_put(tp_mod);
+	return ret;
+}
+
+static int __trace_fprobe_create(int argc, const char *argv[])
+{
+	struct traceprobe_parse_context ctx = {
+		.flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE,
+	};
+	int ret;
+
+	trace_probe_log_init("trace_fprobe", argc, argv);
+	ret = ___trace_fprobe_create(argc, argv, &ctx);
 	traceprobe_finish_parse(&ctx);
 	trace_probe_log_clear();
-	kfree(new_argv);
-	kfree(symbol);
-	kfree(dbuf);
 	return ret;
-
-parse_error:
-	ret = -EINVAL;
-error:
-	free_trace_fprobe(tf);
-	goto out;
 }
 
 static int trace_fprobe_create(const char *raw_command)


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe
  2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
                   ` (4 preceding siblings ...)
  2025-01-07 11:50 ` [PATCH v3 5/5] tracing: Adopt __free() and guard() for trace_fprobe.c Masami Hiramatsu (Google)
@ 2025-01-07 11:53 ` Masami Hiramatsu
  5 siblings, 0 replies; 13+ messages in thread
From: Masami Hiramatsu @ 2025-01-07 11:53 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Steven Rostedt, Peter Zijlstra, Anil S Keshavamurthy,
	David S . Miller, Mathieu Desnoyers, Oleg Nesterov,
	Tzvetomir Stoyanov, Naveen N Rao, Josh Poimboeuf, Jason Baron,
	Ard Biesheuvel, linux-kernel, linux-trace-kernel

On Tue,  7 Jan 2025 20:50:03 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:

> Hi,
> 
> Here is the 3rd version of the series to fix and cleanup probe events in
> ftrace with __free(). I resend this without dynevent and argv_free
> parts because it has been sent by Steve[1]. And I updated the version
> tag.
> 
> In this version, I fixed some issues[5/7] and update DEFINE_FREE() tag
> name to specify freeing function name so that reader can understand it
> easily[2/7].
> Also, I added trace_fprobe cleanup with free[7/7].

Ah, these numbers should be updated. So fixed some issues in [3/5] and
add trace_fprobe.c update in [5/5].

Thanks,

> 
> Thanks,
> 
> ---
> 
> Masami Hiramatsu (Google) (5):
>       tracing/kprobes: Fix to free objects when failed to copy a symbol
>       tracing: Use __free() in trace_probe for cleanup
>       tracing: Use __free() for kprobe events to cleanup
>       tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos
>       tracing: Adopt __free() and guard() for trace_fprobe.c
> 
> 
>  kernel/trace/trace_fprobe.c |  129 +++++++++++++++++++-----------------------
>  kernel/trace/trace_kprobe.c |  133 ++++++++++++++++++++++---------------------
>  kernel/trace/trace_probe.c  |   52 ++++++-----------
>  3 files changed, 145 insertions(+), 169 deletions(-)
> 
> --
> Masami Hiramatsu (Google) <mhiramat@kernel.org>


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup
  2025-01-07 11:50 ` [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
@ 2025-01-07 15:36   ` Steven Rostedt
  2025-01-08  0:38     ` Masami Hiramatsu
  0 siblings, 1 reply; 13+ messages in thread
From: Steven Rostedt @ 2025-01-07 15:36 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Peter Zijlstra, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Tue,  7 Jan 2025 20:50:25 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:

> @@ -1790,18 +1777,15 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
>  				       offsetof(struct file, f_path.dentry),
>  				       equal ? equal + 1 : tmp);
>  
> -		kfree(tmp);
> +		kfree(no_free_ptr(tmp));

I don't get this? You are telling the compiler not to free tmp, because you
decided to free it yourself? Why not just remove the kfree() here altogether?

-- Steve


>  		if (ret >= bufsize - used)
> -			goto nomem;
> +			return -ENOMEM;
>  		argv[i] = tmpbuf + used;
>  		used += ret + 1;
>  	}
>  
> -	*buf = tmpbuf;
> +	*buf = no_free_ptr(tmpbuf);
>  	return 0;
> -nomem:
> -	kfree(tmpbuf);
> -	return -ENOMEM;
>  }

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup
  2025-01-07 11:50 ` [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
@ 2025-01-07 15:42   ` Steven Rostedt
  2025-01-08  0:40     ` Masami Hiramatsu
  0 siblings, 1 reply; 13+ messages in thread
From: Steven Rostedt @ 2025-01-07 15:42 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Peter Zijlstra, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Tue,  7 Jan 2025 20:50:35 +0900
"Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:

> @@ -1898,7 +1899,8 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
>  			  bool is_return)
>  {
>  	enum probe_print_type ptype;
> -	struct trace_kprobe *tk;
> +	struct trace_kprobe *tk __free(free_trace_kprobe) = NULL;
> +	struct trace_probe *tp;
>  	int ret;
>  	char *event;
>  
> @@ -1929,19 +1931,16 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
>  
>  	ptype = trace_kprobe_is_return(tk) ?
>  		PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
> -	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0) {
> -		ret = -ENOMEM;
> -		goto error;
> -	}
> +	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0)
> +		return ERR_PTR(-ENOMEM);
>  
>  	ret = __register_trace_kprobe(tk);
>  	if (ret < 0)
> -		goto error;
> +		return ERR_PTR(ret);
>  
> -	return trace_probe_event_call(&tk->tp);
> -error:
> -	free_trace_kprobe(tk);
> -	return ERR_PTR(ret);


> +	tp = &tk->tp;
> +	tk = NULL;	/* 'tk' is registered successfully, so do not free. */

I wonder if we could change the above to just:

	tp = &(no_free_ptr(tk)->tp);

?

-- Steve

> +	return trace_probe_event_call(tp);
>  }
>  
>  void destroy_local_trace_kprobe(struct trace_event_call *event_call)


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup
  2025-01-07 15:36   ` Steven Rostedt
@ 2025-01-08  0:38     ` Masami Hiramatsu
  2025-01-08  1:34       ` Steven Rostedt
  0 siblings, 1 reply; 13+ messages in thread
From: Masami Hiramatsu @ 2025-01-08  0:38 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Peter Zijlstra, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Tue, 7 Jan 2025 10:36:43 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Tue,  7 Jan 2025 20:50:25 +0900
> "Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> 
> > @@ -1790,18 +1777,15 @@ int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
> >  				       offsetof(struct file, f_path.dentry),
> >  				       equal ? equal + 1 : tmp);
> >  
> > -		kfree(tmp);
> > +		kfree(no_free_ptr(tmp));
> 
> I don't get this? You are telling the compiler not to free tmp, because you
> decided to free it yourself? Why not just remove the kfree() here altogether?

In the for-loop block, the __free() work only when we exit the loop, not
each iteration. In each iteration, kstrdup() is assigned to the 'tmp',
so we need to kfree() each time.

Hmm, maybe this is a sign that I should not use __free() for the 'tmp',
or I should call kfree(tmp) right before kstrdup(), like below.

 	for (i = 0; i < argc; i++) {
		char *tmp __free(kfree) = NULL;
		...
		kfree(tmp);
		tmp = kstrdup(argv[i], GFP_KERNEL);
	}

Does this make sense?

> 
> -- Steve
> 
> 
> >  		if (ret >= bufsize - used)
> > -			goto nomem;
> > +			return -ENOMEM;
> >  		argv[i] = tmpbuf + used;
> >  		used += ret + 1;
> >  	}
> >  
> > -	*buf = tmpbuf;
> > +	*buf = no_free_ptr(tmpbuf);
> >  	return 0;
> > -nomem:
> > -	kfree(tmpbuf);
> > -	return -ENOMEM;
> >  }


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup
  2025-01-07 15:42   ` Steven Rostedt
@ 2025-01-08  0:40     ` Masami Hiramatsu
  0 siblings, 0 replies; 13+ messages in thread
From: Masami Hiramatsu @ 2025-01-08  0:40 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Peter Zijlstra, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Tue, 7 Jan 2025 10:42:31 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Tue,  7 Jan 2025 20:50:35 +0900
> "Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> 
> > @@ -1898,7 +1899,8 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
> >  			  bool is_return)
> >  {
> >  	enum probe_print_type ptype;
> > -	struct trace_kprobe *tk;
> > +	struct trace_kprobe *tk __free(free_trace_kprobe) = NULL;
> > +	struct trace_probe *tp;
> >  	int ret;
> >  	char *event;
> >  
> > @@ -1929,19 +1931,16 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
> >  
> >  	ptype = trace_kprobe_is_return(tk) ?
> >  		PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
> > -	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0) {
> > -		ret = -ENOMEM;
> > -		goto error;
> > -	}
> > +	if (traceprobe_set_print_fmt(&tk->tp, ptype) < 0)
> > +		return ERR_PTR(-ENOMEM);
> >  
> >  	ret = __register_trace_kprobe(tk);
> >  	if (ret < 0)
> > -		goto error;
> > +		return ERR_PTR(ret);
> >  
> > -	return trace_probe_event_call(&tk->tp);
> > -error:
> > -	free_trace_kprobe(tk);
> > -	return ERR_PTR(ret);
> 
> 
> > +	tp = &tk->tp;
> > +	tk = NULL;	/* 'tk' is registered successfully, so do not free. */
> 
> I wonder if we could change the above to just:
> 
> 	tp = &(no_free_ptr(tk)->tp);

Ah, that's nice idea. Then I can remove 'tp' as;

	return trace_probe_event_call(&(no_free_ptr(tk)->tp));

Thanks!

> 
> ?
> 
> -- Steve
> 
> > +	return trace_probe_event_call(tp);
> >  }
> >  
> >  void destroy_local_trace_kprobe(struct trace_event_call *event_call)
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup
  2025-01-08  0:38     ` Masami Hiramatsu
@ 2025-01-08  1:34       ` Steven Rostedt
  2025-01-08  2:03         ` Masami Hiramatsu
  0 siblings, 1 reply; 13+ messages in thread
From: Steven Rostedt @ 2025-01-08  1:34 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Peter Zijlstra, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Wed, 8 Jan 2025 09:38:43 +0900
Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:

> > I don't get this? You are telling the compiler not to free tmp, because you
> > decided to free it yourself? Why not just remove the kfree() here altogether?  
> 
> In the for-loop block, the __free() work only when we exit the loop, not
> each iteration. In each iteration, kstrdup() is assigned to the 'tmp',
> so we need to kfree() each time.

Really? It doesn't trigger for each iteration? That's rather unintuitive. :-/
And sounds buggy, as wouldn't that then cause a memory leak?

I would say not to use __free() for tmp at all. Because now it's just
getting confusing.

-- Steve


> 
> Hmm, maybe this is a sign that I should not use __free() for the 'tmp',
> or I should call kfree(tmp) right before kstrdup(), like below.
> 
>  	for (i = 0; i < argc; i++) {
> 		char *tmp __free(kfree) = NULL;
> 		...
> 		kfree(tmp);
> 		tmp = kstrdup(argv[i], GFP_KERNEL);
> 	}
> 
> Does this make sense?


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup
  2025-01-08  1:34       ` Steven Rostedt
@ 2025-01-08  2:03         ` Masami Hiramatsu
  0 siblings, 0 replies; 13+ messages in thread
From: Masami Hiramatsu @ 2025-01-08  2:03 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Peter Zijlstra, Anil S Keshavamurthy, David S . Miller,
	Mathieu Desnoyers, Oleg Nesterov, Tzvetomir Stoyanov,
	Naveen N Rao, Josh Poimboeuf, Jason Baron, Ard Biesheuvel,
	linux-kernel, linux-trace-kernel

On Tue, 7 Jan 2025 20:34:32 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed, 8 Jan 2025 09:38:43 +0900
> Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
> 
> > > I don't get this? You are telling the compiler not to free tmp, because you
> > > decided to free it yourself? Why not just remove the kfree() here altogether?  
> > 
> > In the for-loop block, the __free() work only when we exit the loop, not
> > each iteration. In each iteration, kstrdup() is assigned to the 'tmp',
> > so we need to kfree() each time.
> 
> Really? It doesn't trigger for each iteration? That's rather unintuitive. :-/
> And sounds buggy, as wouldn't that then cause a memory leak?

Ahh, sorry, it was my misunderstood. I made a test code and confirmed that
kfree() is called in each iteration. Previously I checked but I confused the result.

----------
#include <stdio.h>

void count_func(int *p)
{
	printf("Scope out: %d\n", *p);
}

int main(void)
{
	for (int i = 0; i < 10; i++) {
		int j __attribute((cleanup(count_func))) = 0;

		j++;
	}
	return 0;
}
----------

$ ./loop_cleanup 
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1
Scope out: 1

Let me fix that.

Thanks,

> 
> I would say not to use __free() for tmp at all. Because now it's just
> getting confusing.
> 
> -- Steve
> 
> 
> > 
> > Hmm, maybe this is a sign that I should not use __free() for the 'tmp',
> > or I should call kfree(tmp) right before kstrdup(), like below.
> > 
> >  	for (i = 0; i < argc; i++) {
> > 		char *tmp __free(kfree) = NULL;
> > 		...
> > 		kfree(tmp);
> > 		tmp = kstrdup(argv[i], GFP_KERNEL);
> > 	}
> > 
> > Does this make sense?
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-01-08  2:03 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-07 11:50 [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu (Google)
2025-01-07 11:50 ` [PATCH v3 1/5] tracing/kprobes: Fix to free objects when failed to copy a symbol Masami Hiramatsu (Google)
2025-01-07 11:50 ` [PATCH v3 2/5] tracing: Use __free() in trace_probe for cleanup Masami Hiramatsu (Google)
2025-01-07 15:36   ` Steven Rostedt
2025-01-08  0:38     ` Masami Hiramatsu
2025-01-08  1:34       ` Steven Rostedt
2025-01-08  2:03         ` Masami Hiramatsu
2025-01-07 11:50 ` [PATCH v3 3/5] tracing: Use __free() for kprobe events to cleanup Masami Hiramatsu (Google)
2025-01-07 15:42   ` Steven Rostedt
2025-01-08  0:40     ` Masami Hiramatsu
2025-01-07 11:50 ` [PATCH v3 4/5] tracing/kprobes: Simplify __trace_kprobe_create() by removing gotos Masami Hiramatsu (Google)
2025-01-07 11:50 ` [PATCH v3 5/5] tracing: Adopt __free() and guard() for trace_fprobe.c Masami Hiramatsu (Google)
2025-01-07 11:53 ` [PATCH v3 0/5] tracing/probes: Cleanup with guard and __free for kprobe and fprobe Masami Hiramatsu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).