Message ID | 173625062518.1375434.10516553019799245668.stgit@devnote2 (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | tracing/probes: Cleanup with guard and __free for kprobe and fprobe | expand |
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; > }
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; > > }
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?
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? >
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)