Re: [RESEND][PATCH v15 2/4] perf: Support deferred user callchains
From: Steven Rostedt <rostedt@kernel.org>
Date: 2025-09-23 09:35:25
Also in:
bpf, lkml
On Tue, 23 Sep 2025 11:19:35 +0200 Peter Zijlstra [off-list ref] wrote:
On Mon, Sep 08, 2025 at 01:14:14PM -0400, Steven Rostedt wrote:quoted
+static void perf_event_callchain_deferred(struct callback_head *work) +{ + struct perf_event *event = container_of(work, struct perf_event, pending_unwind_work); + struct perf_callchain_deferred_event deferred_event; + u64 callchain_context = PERF_CONTEXT_USER; + struct unwind_stacktrace trace; + struct perf_output_handle handle; + struct perf_sample_data data; + u64 nr; + + if (!event->pending_unwind_callback) + return; + + if (unwind_user_faultable(&trace) < 0) + goto out;This is broken. Because:quoted
+ + /* + * All accesses to the event must belong to the same implicit RCU + * read-side critical section as the ->pending_unwind_callback reset. + * See comment in perf_pending_unwind_sync(). + */ + guard(rcu)();Here you start a guard, that lasts until close of function..quoted
+ + if (current->flags & (PF_KTHREAD | PF_USER_WORKER)) + goto out; + + nr = trace.nr + 1 ; /* '+1' == callchain_context */ + + deferred_event.header.type = PERF_RECORD_CALLCHAIN_DEFERRED; + deferred_event.header.misc = PERF_RECORD_MISC_USER; + deferred_event.header.size = sizeof(deferred_event) + (nr * sizeof(u64)); + + deferred_event.nr = nr; + deferred_event.cookie = unwind_user_get_cookie(); + + perf_event_header__init_id(&deferred_event.header, &data, event); + + if (perf_output_begin(&handle, &data, event, deferred_event.header.size)) + goto out; + + perf_output_put(&handle, deferred_event); + perf_output_put(&handle, callchain_context); + /* trace.entries[] are not guaranteed to be 64bit */ + for (int i = 0; i < trace.nr; i++) { + u64 entry = trace.entries[i]; + perf_output_put(&handle, entry); + } + perf_event__output_id_sample(event, &handle, &data); + + perf_output_end(&handle); + +out:Which very much includes here, so your goto jumps into a scope, which is not permitted.
Nice catch.
GCC can fail to warn on this, but clang will consistently fail to compile this. Surely the robot would've told you by now -- even if you're not using clang yourself.
Unfortunately it hasn't :-( I need to start building with clang more often. I even pushed this to a git tree. Not sure why it didn't get flagged. -- Steve