Re: [BUG] KCSAN cannot find frame in stack trace
From: Paul E. McKenney
Date: Fri Oct 30 2026 - 10:25:17 EST
On Fri, Oct 30, 2026 at 08:33:55AM +0000, Marco Elver wrote:
> On Thu, Oct 29, 2026 at 05:10PM -0700, Paul E. McKenney wrote:
> > Hello!
> >
> > I am seeing the following (very) intermittent spat when running
> > the rcutorture script torture.sh on recent -next (starting about
> > next-20261014) with KCSAN enabled:
>
> I think there's no reason why this should happen more often. Maybe the
> torture testing or your system became better at exposing this?
Quite possibly. An effective test suite never stands still. ;-)
> [...]
> > This is the code at line 344 of kernel/kcsan/report.c:
> >
> > /* Should not happen; the resulting stack trace is likely misleading. */
> > WARN_ONCE(1, "Cannot find frame for %pS in stack trace", (void *)ip);
> >
> > This does not happen often enough for reasonable bisection. However, the
> > alleged fix below does seem to prevent this from happening. This alleged
> > fix should of course be considered to be part of the bug report: I am
> > *not* claiming that it is a proper fix.
> >
> > The diagnosis sounds plausible to me, but perhaps not to those who
> > understand the affected code better than I do. And I don't know why
> > this wouldn't have been showing up earlier.
> >
> > Thoughts?
> >
> > Thanx, Paul
> >
> > ------------------------------------------------------------------------
> > LLM alleged fix:
> > ------------------------------------------------------------------------
> >
> > kcsan: reset per-task KCSAN state in dup_task_struct
>
> Yes, it's very plausible and the stack-trace and WARN all line up.
Whew!!!
> We don't need to reset kcsan_save_irqtrace as that's guaranteed to be
> overwritten before reading out again.
>
> Updated fix below; it's basically identical, except for
> kcsan_save_irqtrace. Let me know if I can either add your
> SOB+Co-authored-by, or you send it out as a PATCH yourself.
Please do send it out. A Reported-by will more than suffice. It is
not like I put any of my own effort into that patch. ;-)
But if (and only if) your procedures absolutely require it:
Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
Thanx, Paul
> Thanks,
> -- Marco
>
> ------ >8 ------
>
> From: Marco Elver <elver@xxxxxxxxxx>
> Date: Fri, 30 Oct 2026 00:46:03 +0000
> Subject: [PATCH] kcsan: Reset per-task KCSAN state on fork
>
> arch_dup_task_struct() copies the parent's task_struct verbatim, which
> includes kcsan_ctx and kcsan_stack_depth; nothing reinitializes them for
> the child.
>
> With CONFIG_KCSAN_WEAK_MEMORY this leaks a live reorder_access: an
> access whose simulated reordering is only valid until the parent returns
> from the frame that performed it (tracked via kcsan_stack_depth and
> cleared by __tsan_func_exit()). The child inherits both the entry and
> the parent's stack depth, but never returns through the parent's frames,
> so the entry is never invalidated and is replayed on every subsequent
> check_access() of the child.
>
> The most direct way to hit this is the copy itself: __tsan_memcpy()
> runs check_access() on the destination before copying. If that access is
> selected for a watchpoint, set_reorder_access() records it (ptr = the
> child's task_struct, ip in arch_dup_task_struct()) in the parent's ctx,
> and the memcpy then copies that entry into the child. For an idle task
> created by fork_idle(), the stale access covers thread_info.flags, which
> other CPUs frequently access, resulting in false positive reports and:
>
> WARNING: kernel/kcsan/report.c:344 at sanitize_stack_entries+0x120/0x12c
> Cannot find frame for arch_dup_task_struct+0x40/0x154 in stack trace
> ...
> Call trace:
> sanitize_stack_entries+0x120/0x12c (P)
> print_report+0x84/0x488
> kcsan_report_known_origin+0x14c/0x1ec
> kcsan_setup_watchpoint+0x578/0x864
> __kcsan_check_access+0x1ec/0x1f8
> do_raw_spin_lock+0xa4/0x1c4
> _raw_spin_lock+0x70/0x88
> rcutree_report_cpu_starting+0x1ac/0x4b8
> secondary_start_kernel+0xe8/0x28c
> __secondary_switched+0xc0/0xc4
>
> Reset the child's KCSAN state in dup_task_struct() after the copy,
> alongside the existing kcov/kmsan initializers.
>
> Reported-by: Paul E. McKenney <paulmck@xxxxxxxxxx>
> Link: https://lore.kernel.org/all/97f6213a-1dec-494e-96d1-abe546bce993@paulmck-laptop/
> Fixes: 69562e4983d9 ("kcsan: Add core support for a subset of weak memory modeling")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Marco Elver <elver@xxxxxxxxxx>
> ---
> include/linux/kcsan.h | 10 ++++++++++
> kernel/fork.c | 2 ++
> kernel/kcsan/core.c | 16 ++++++++++++++++
> 3 files changed, 28 insertions(+)
>
> diff --git a/include/linux/kcsan.h b/include/linux/kcsan.h
> index c07c71f5ba4f..c7e9d15dd7bd 100644
> --- a/include/linux/kcsan.h
> +++ b/include/linux/kcsan.h
> @@ -13,6 +13,8 @@
> #include <linux/kcsan-checks.h>
> #include <linux/types.h>
>
> +struct task_struct;
> +
> #ifdef CONFIG_KCSAN
>
> /*
> @@ -66,9 +68,17 @@ struct kcsan_ctx {
> */
> void kcsan_init(void);
>
> +/**
> + * kcsan_task_init - initialize KCSAN state of a new task
> + *
> + * @task: task to initialize; must have been copied from its parent already.
> + */
> +void kcsan_task_init(struct task_struct *task);
> +
> #else /* CONFIG_KCSAN */
>
> static inline void kcsan_init(void) { }
> +static inline void kcsan_task_init(struct task_struct *task) { }
>
> #endif /* CONFIG_KCSAN */
>
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 5ef413368912..62a096ca8dce 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -93,6 +93,7 @@
> #include <linux/compiler.h>
> #include <linux/sysctl.h>
> #include <linux/kcov.h>
> +#include <linux/kcsan.h>
> #include <linux/livepatch.h>
> #include <linux/thread_info.h>
> #include <linux/kstack_erase.h>
> @@ -986,6 +987,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
>
> kcov_task_init(tsk);
> kmsan_task_create(tsk);
> + kcsan_task_init(tsk);
> kmap_local_fork(tsk);
>
> #ifdef CONFIG_FAULT_INJECTION
> diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c
> index a3aa5e5b039d..d19d60ad007a 100644
> --- a/kernel/kcsan/core.c
> +++ b/kernel/kcsan/core.c
> @@ -828,6 +828,22 @@ void __init kcsan_init(void)
> }
> }
>
> +void kcsan_task_init(struct task_struct *task)
> +{
> + /*
> + * arch_dup_task_struct() copies the parent's kcsan_ctx verbatim,
> + * including a reorder_access that is still live in the parent's frame
> + * (e.g. the write of the copy itself). The child never returns through
> + * that frame, so it would replay the stale access indefinitely, causing
> + * false positives and "Cannot find frame" warnings in replace_stack_entry().
> + */
> + memset(&task->kcsan_ctx, 0, sizeof(task->kcsan_ctx));
> + task->kcsan_ctx.scoped_accesses = (struct list_head){ LIST_POISON1, NULL };
> +#ifdef CONFIG_KCSAN_WEAK_MEMORY
> + task->kcsan_stack_depth = 0;
> +#endif
> +}
> +
> /* === Exported interface =================================================== */
>
> void kcsan_disable_current(void)
> --
> 2.56.0.317.g454f8302e1-goog
>