This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch releases/13.0
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/releases/13.0 by this push:
new 69d7833fbab sched/backtrace: fix cross-CPU buffer access under addrenv
69d7833fbab is described below
commit 69d7833fbabc78030f4477e87da66687e5db7873
Author: liang.huang <[email protected]>
AuthorDate: Sun Jul 19 17:45:39 2026 +0800
sched/backtrace: fix cross-CPU buffer access under addrenv
The remote CPU's IPI handler wrote into the caller's buffer directly,
which may not be reachable from the target CPU's address environment
under CONFIG_ARCH_ADDRENV.
Signed-off-by: liang.huang <[email protected]>
---
sched/sched/sched_backtrace.c | 97 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 93 insertions(+), 4 deletions(-)
diff --git a/sched/sched/sched_backtrace.c b/sched/sched/sched_backtrace.c
index 40c993c0a05..b16e29bf7ee 100644
--- a/sched/sched/sched_backtrace.c
+++ b/sched/sched/sched_backtrace.c
@@ -28,15 +28,36 @@
#include <nuttx/sched.h>
#include <nuttx/init.h>
+#include <sys/param.h>
+
+#include <string.h>
+
#include "sched.h"
#ifdef CONFIG_ARCH_HAVE_BACKTRACE
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_SMP) && defined(CONFIG_ARCH_ADDRENV)
+
+/* Depth of the scratch buffer used to relay a remote backtrace back to
+ * the caller, since the caller's own buffer may not be mapped in the
+ * address environment active on the target CPU. Requests larger than
+ * this are serviced over multiple round trips.
+ */
+
+#define BACKTRACE_SCRATCH_DEPTH 32
+
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
#ifdef CONFIG_SMP
+
struct backtrace_arg_s
{
pid_t pid;
@@ -105,6 +126,11 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int
size, int skip)
FAR struct tcb_s *tcb = this_task();
int ret = 0;
+ if (size <= 0 || buffer == NULL)
+ {
+ return 0;
+ }
+
if (tcb->pid == tid)
{
ret = up_backtrace(tcb, buffer, size, skip);
@@ -121,25 +147,88 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int
size, int skip)
tcb->task_state == TSTATE_TASK_RUNNING)
{
struct backtrace_arg_s arg;
+ bool need_restore;
+#ifdef CONFIG_ARCH_ADDRENV
+ FAR void *scratch[BACKTRACE_SCRATCH_DEPTH];
+#endif
if ((tcb->flags & TCB_FLAG_CPU_LOCKED) != 0)
{
- arg.pid = tcb->pid;
- arg.need_restore = false;
+ need_restore = false;
}
else
{
- arg.pid = tcb->pid;
- arg.need_restore = true;
+ need_restore = true;
tcb->flags |= TCB_FLAG_CPU_LOCKED;
}
+ arg.pid = tcb->pid;
+
+#ifdef CONFIG_ARCH_ADDRENV
+ arg.buffer = scratch;
+
+ while (ret < size)
+ {
+ arg.size = MIN(size - ret, BACKTRACE_SCRATCH_DEPTH);
+ arg.skip = skip + ret;
+
+ /* If this round's request covers all remaining
+ * frames (i.e. it was not capped by the scratch
+ * buffer), there is nothing left to loop for
+ * afterwards, so it is safe to have it release the
+ * pin as well and skip the data-less round below.
+ */
+
+ arg.need_restore = need_restore &&
+ arg.size == size - ret;
+
+ if (nxsched_smp_call_single(tcb->cpu,
+ sched_backtrace_handler,
+ &arg) < 0)
+ {
+ break;
+ }
+
+ if (arg.need_restore)
+ {
+ need_restore = false;
+ }
+
+ memcpy(&buffer[ret], scratch,
+ arg.stacksize * sizeof(FAR void *));
+ ret += arg.stacksize;
+
+ if (arg.stacksize < arg.size)
+ {
+ /* Reached the bottom of the target's stack. */
+
+ break;
+ }
+ }
+
+ /* The loop above may have exited without a round
+ * releasing the pin (e.g. it broke out on reaching the
+ * bottom of the stack before a "guaranteed last round"
+ * occurred). Send one more, data-less round purely to
+ * release it.
+ */
+
+ if (need_restore)
+ {
+ arg.size = 0;
+ arg.need_restore = true;
+ nxsched_smp_call_single(tcb->cpu, sched_backtrace_handler,
+ &arg);
+ }
+#else
+ arg.need_restore = need_restore;
arg.buffer = buffer;
arg.size = size;
arg.skip = skip;
ret = nxsched_smp_call_single(tcb->cpu,
sched_backtrace_handler,
&arg) < 0 ? 0 : arg.stacksize;
+#endif
}
else
#endif