On Mon, Sep 08, 2025 at 01:14:14PM -0400, Steven Rostedt wrote: > +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: > + > + /* > + * 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.. > + > + 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. 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. > + event->pending_unwind_callback = 0; > + local_dec(&event->ctx->nr_no_switch_fast); > + rcuwait_wake_up(&event->pending_unwind_wait); > +}