sched: Improve nxsched stack overflow checking implementation

1. Remove STACKCHECK_SOFTWARE config,
   2. Do sp value checking when STACKCHECK_MARGIN == 0,
   3. Do margin-based stack check when STACKCHECK_MARGIN > 0,
   4. Disable stack check when STACKCHECK_MARGIN == -1

Signed-off-by: Chengdong Wang <wangchengdong@lixiang.com>
This commit is contained in:
wangchengdong
2025-10-01 21:46:38 +08:00
committed by Xiang Xiao
parent 1210dc4919
commit 07a470f696
8 changed files with 119 additions and 30 deletions
+1 -2
View File
@@ -56,8 +56,7 @@ Stack Overflow Software Check During Context Switching
2. Check if the sp register is out of bounds.
Usage:
Enable CONFIG_STACKCHECK_SOFTWARE
You can set the detection length by STACKCHECK_MARGIN
Set the detection length by STACKCHECK_MARGIN
Stack Overflow Hardware Check
-----------------------------
+3 -13
View File
@@ -2455,23 +2455,13 @@ config STACK_COLORATION
Only supported by a few architectures.
config STACKCHECK_SOFTWARE
bool "Software detection of stack overflow"
depends on STACK_COLORATION && DEBUG_ASSERTIONS
---help---
When switching contexts, it will detect whether a stack overflow occurs.
Two methods are used here.
The first is to check the legitimacy of the value of the sp register;
the second is to check the specified number of bytes at the bottom of the stack.
If either of these two methods fails, an ASSERT will be triggered.
config STACKCHECK_MARGIN
int "Stack overflow check size (bytes)"
depends on STACKCHECK_SOFTWARE
default 16
depends on DEBUG_ASSERTIONS
default -1
---help---
Specifies the number of bytes at the end of the stack to check for overflow.
A value of 0 disables additional checking. Increase this value for stricter
A value of -1 disables additional checking. Increase this value for stricter
overflow detection, at the cost of additional overhead.
config STACK_CANARIES
+1 -1
View File
@@ -158,7 +158,7 @@ void irq_dispatch(int irq, FAR void *context)
}
#endif
#if defined(CONFIG_STACKCHECK_SOFTWARE) && CONFIG_STACKCHECK_MARGIN > 0
#if defined(CONFIG_STACKCHECK_MARGIN) && (CONFIG_STACKCHECK_MARGIN > 0)
DEBUGASSERT(up_check_intstack(this_cpu(),
CONFIG_STACKCHECK_MARGIN) == 0);
#endif
+6
View File
@@ -49,6 +49,12 @@ set(SRCS
sched_get_stateinfo.c
sched_switchcontext.c)
if(DEFINED CONFIG_STACKCHECK_MARGIN)
if(NOT CONFIG_STACKCHECK_MARGIN EQUAL -1)
list(APPEND SRCS nxsched_checkstackoverflow.c)
endif()
endif()
if(CONFIG_PRIORITY_INHERITANCE)
list(APPEND SRCS sched_reprioritize.c)
endif()
+6
View File
@@ -32,6 +32,12 @@ CSRCS += sched_idletask.c sched_self.c sched_get_stackinfo.c sched_get_tls.c
CSRCS += sched_sysinfo.c sched_get_stateinfo.c sched_getcpu.c
CSRCS += sched_switchcontext.c
ifneq ($(CONFIG_STACKCHECK_MARGIN),)
ifneq ($(CONFIG_STACKCHECK_MARGIN),-1)
CSRCS += nxsched_checkstackoverflow.c
endif
endif
ifeq ($(CONFIG_PRIORITY_INHERITANCE),y)
CSRCS += sched_reprioritize.c
endif
+94
View File
@@ -0,0 +1,94 @@
/****************************************************************************
* sched/sched/nxsched_checkstackoverflow.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <time.h>
#include <assert.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/sched_note.h>
#include "sched/sched.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxsched_checkstackoverflow
*
* Description:
* Verify that the specified thread has not overflowed its stack.
*
* Behavior depends on CONFIG_STACKCHECK_MARGIN:
*
* - CONFIG_STACKCHECK_MARGIN == 0:
* Perform a strict boundary check. The current stack pointer must
* remain within the allocated stack region [base, top].
*
* - CONFIG_STACKCHECK_MARGIN > 0:
* Perform an architecture-specific check with a safety margin.
* The stack must not extend beyond the reserved margin area.
*
* - CONFIG_STACKCHECK_MARGIN < 0:
* Stack checking is disabled at build time. In this case, calls to
* nxsched_checkstackoverflow() are replaced with a no-op macro.
*
* Input Parameters:
* tcb - Pointer to the TCB of the thread to be checked.
*
* Returned Value:
* None. The function will trigger a DEBUGASSERT if a stack overflow
* condition is detected.
*
****************************************************************************/
void nxsched_checkstackoverflow(FAR struct tcb_s *tcb)
{
#if (CONFIG_STACKCHECK_MARGIN == 0)
/* Strict stack pointer check:
* SP must remain within the allocated stack boundaries.
*/
if (tcb->xcp.regs != NULL)
{
uintptr_t sp = up_getusrsp(tcb->xcp.regs);
uintptr_t top = (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size;
uintptr_t bot = (uintptr_t)tcb->stack_base_ptr;
DEBUGASSERT(sp > bot && sp <= top);
}
#elif defined(CONFIG_STACK_COLORATION) && (CONFIG_STACKCHECK_MARGIN > 0)
/* Margin-based stack check:
* Allow some reserved margin area before reporting overflow.
*/
DEBUGASSERT(up_check_tcbstack(tcb, CONFIG_STACKCHECK_MARGIN) == 0);
#endif
}
+7
View File
@@ -393,6 +393,13 @@ static inline_function FAR struct tcb_s *this_task(void)
}
#endif
#if defined(CONFIG_STACKCHECK_MARGIN) && \
(CONFIG_STACKCHECK_MARGIN != -1)
void nxsched_checkstackoverflow(FAR struct tcb_s *tcb);
#else
# define nxsched_checkstackoverflow(tcb)
#endif
#ifdef CONFIG_SMP
bool nxsched_switch_running(int cpu, bool switch_equal);
void nxsched_process_delivered(int cpu);
+1 -14
View File
@@ -49,20 +49,7 @@
void nxsched_switch_context(FAR struct tcb_s *from, FAR struct tcb_s *to)
{
#ifdef CONFIG_STACKCHECK_SOFTWARE
if (from->xcp.regs)
{
uintptr_t sp = up_getusrsp(from->xcp.regs);
uintptr_t top = (uintptr_t)from->stack_base_ptr + from->adj_stack_size;
uintptr_t bottom = (uintptr_t)from->stack_base_ptr;
DEBUGASSERT(sp > bottom && sp <= top);
}
#if CONFIG_STACKCHECK_MARGIN > 0
DEBUGASSERT(up_check_tcbstack(from, CONFIG_STACKCHECK_MARGIN) == 0);
#endif
#endif
nxsched_checkstackoverflow(from);
#ifdef CONFIG_SCHED_SPORADIC
/* Perform sporadic schedule operations */