操作系统栈溢出检測之ucosII篇

操作系统栈溢出检測之ucosII篇

大家好,又见面了,我是全栈君。

操作系统栈溢出检測之uc/osII篇

Author               :       David Lin (林鹏)

E-mail               :       linpeng1577@gmail.com  linpeng1577@163.com  15820224344@163.com

OS                   :       源代码级理解掌握Ucos,Rt-thread等嵌入式操作系统内核的设计与实现,眼下在研究linux内核,路漫漫其修远兮,吾将上下而求索 :)

转载请注明出处,谢谢

前言:

         在嵌入式操作系统执行中。进程的栈溢出问题是大家比較关心的问题。由于资源限制。栈大小受到限制,本文主要介绍uc/os自带的栈检測机制(为什么是ucos,而不是ecos或者其它,由于我如今项目用这个,兴许有时间再介绍一种更简单通用。不依赖详细操作系统的栈溢出检測机制)。

原理:

         1.在进程的栈初始化的时候。按预设的字节对齐方式,用特定魔数(比方0x9527,ucosII预设是0值)将栈元素依次完毕初始化;

         2.在系统执行的时候,通过守护进程。依次遍历各个进程的栈。检測栈元素的值是否等于初始化的魔数,求得被污染的元素个数所占栈大小的比例,即为栈使用量。

         3.不通过守护进程,直接对进程进行栈溢出检測是否可行?能够。只是不推荐在进程内部或者进程调度的时候进行如此使用量检測。即使使用二分查找算法进行优化,假设栈大到一定程度,效 率问题还是须要谨慎考虑的;

         4.不扯为什么这么设计这些事情了,这跟小学语文写作者的中心思想一样,不是ucos原作者,所以不写,你想知道Jean J. Labrosse怎么想的,能够给他发邮件:-)

系统版本号:uc/osII V2.85

开发环境:IAR for ARM (为什么不在linux下开发,我也想知道。

                    由于我喜欢gnu/linux,喜欢用gcc,gdb,vim,make,(⊙o⊙)…。只是,你懂的:-)                     

1.      相关宏定义os_cfg.h

#defineOS_TASK_STAT_EN                        1  /* Enable (1) or Disable(0) the statistics task*/

#defineOS_TASK_STAT_STK_CHK_EN   1  /* Check task stacks from statistic task          */

 

2.      相关函数os_core.c os_task.c

static  void OS_InitTaskStat (void) {……};     //初始化栈守护进程,看哪个进程最贪吃 :-)

/*
*********************************************************************************************************
*                                             INITIALIZATION
*                                      CREATING THE STATISTIC TASK
*
* Description: This function creates the Statistic Task.
*
* Arguments  : none
*
* Returns    : none
*********************************************************************************************************
*/

#if OS_TASK_STAT_EN > 0
static  void  OS_InitTaskStat (void)
{
#if OS_TASK_NAME_SIZE > 7
    INT8U  err;
#endif


#if OS_TASK_CREATE_EXT_EN > 0
    #if OS_STK_GROWTH == 1
    (void)OSTaskCreateExt(OS_TaskStat,
                          (void *)0,                                   /* No args passed to OS_TaskStat()*/
                          &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Top-Of-Stack               */
                          OS_TASK_STAT_PRIO,                           /* One higher than the idle task  */
                          OS_TASK_STAT_ID,
                          &OSTaskStatStk[0],                           /* Set Bottom-Of-Stack            */
                          OS_TASK_STAT_STK_SIZE,
                          (void *)0,                                   /* No TCB extension               */
                          OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
    #else
    (void)OSTaskCreateExt(OS_TaskStat,
                          (void *)0,                                   /* No args passed to OS_TaskStat()*/
                          &OSTaskStatStk[0],                           /* Set Top-Of-Stack               */
                          OS_TASK_STAT_PRIO,                           /* One higher than the idle task  */
                          OS_TASK_STAT_ID,
                          &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],   /* Set Bottom-Of-Stack            */
                          OS_TASK_STAT_STK_SIZE,
                          (void *)0,                                   /* No TCB extension               */
                          OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);  /* Enable stack checking + clear  */
    #endif
#else
    #if OS_STK_GROWTH == 1
    (void)OSTaskCreate(OS_TaskStat,
                       (void *)0,                                      /* No args passed to OS_TaskStat()*/
                       &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1],      /* Set Top-Of-Stack               */
                       OS_TASK_STAT_PRIO);                             /* One higher than the idle task  */
    #else
    (void)OSTaskCreate(OS_TaskStat,
                       (void *)0,                                      /* No args passed to OS_TaskStat()*/
                       &OSTaskStatStk[0],                              /* Set Top-Of-Stack               */
                       OS_TASK_STAT_PRIO);                             /* One higher than the idle task  */
    #endif
#endif

#if OS_TASK_NAME_SIZE > 14
    OSTaskNameSet(OS_TASK_STAT_PRIO, (INT8U *)"uC/OS-II Stat", &err);
#else
#if OS_TASK_NAME_SIZE > 7
    OSTaskNameSet(OS_TASK_STAT_PRIO, (INT8U *)"OS-Stat", &err);
#endif
#endif
}
#endif

#if OS_TASK_CREATE_EXT_EN > 0

void  OS_TaskStkClr (OS_STK *pbos, INT32U size,INT16U opt) {……};  //用于栈初始化

#endif

/*
*********************************************************************************************************
*                                        CLEAR TASK STACK
*
* Description: This function is used to clear the stack of a task (i.e. write all zeros)
*
* Arguments  : pbos     is a pointer to the task's bottom of stack.  If the configuration constant
*                       OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high
*                       memory to low memory).  'pbos' will thus point to the lowest (valid) memory
*                       location of the stack.  If OS_STK_GROWTH is set to 0, 'pbos' will point to the
*                       highest memory location of the stack and the stack will grow with increasing
*                       memory locations.  'pbos' MUST point to a valid 'free' data item.
*
*              size     is the number of 'stack elements' to clear.
*
*              opt      contains additional information (or options) about the behavior of the task.  The
*                       LOWER 8-bits are reserved by uC/OS-II while the upper 8 bits can be application
*                       specific.  See OS_TASK_OPT_??

? in uCOS-II.H.** Returns : none**********************************************************************************************************/#if OS_TASK_CREATE_EXT_EN > 0void OS_TaskStkClr (OS_STK *pbos, INT32U size, INT16U opt){ if ((opt & OS_TASK_OPT_STK_CHK) != 0x0000) { /* See if stack checking has been enabled */ if ((opt & OS_TASK_OPT_STK_CLR) != 0x0000) { /* See if stack needs to be cleared */#if OS_STK_GROWTH == 1 while (size > 0) { /* Stack grows from HIGH to LOW memory */ size--; *pbos++ = (OS_STK)0; /* Clear from bottom of stack and up! */ }#else while (size > 0) { /* Stack grows from LOW to HIGH memory */ size--; *pbos-- = (OS_STK)0; /* Clear from bottom of stack and down */ }#endif } }}#endif

#if OS_TASK_CREATE_EXT_EN > 0

INT8U OSTaskStkChk (INT8U prio, OS_STK_DATA *p_stk_data) {……}; 

//用于检測各个进程的栈使用率,被守护进程OS_TaskStat(void *p_arg)调用

#endif

/*
*********************************************************************************************************
*                                             STACK CHECKING
*
* Description: This function is called to check the amount of free memory left on the specified task's
*              stack.
*
* Arguments  : prio          is the task priority
*
*              p_stk_data    is a pointer to a data structure of type OS_STK_DATA.
*
* Returns    : OS_ERR_NONE            upon success
*              OS_ERR_PRIO_INVALID    if the priority you specify is higher that the maximum allowed
*                                     (i.e. > OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.
*              OS_ERR_TASK_NOT_EXIST  if the desired task has not been created or is assigned to a Mutex PIP
*              OS_ERR_TASK_OPT        if you did NOT specified OS_TASK_OPT_STK_CHK when the task was created
*              OS_ERR_PDATA_NULL      if 'p_stk_data' is a NULL pointer
*********************************************************************************************************
*/
#if OS_TASK_CREATE_EXT_EN > 0
INT8U  OSTaskStkChk (INT8U prio, OS_STK_DATA *p_stk_data)
{
    OS_TCB    *ptcb;
    OS_STK    *pchk;
    INT32U     free;
    INT32U     size;
#if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0;
#endif



#if OS_ARG_CHK_EN > 0
    if (prio > OS_LOWEST_PRIO) {                       /* Make sure task priority is valid             */
        if (prio != OS_PRIO_SELF) {
            return (OS_ERR_PRIO_INVALID);
        }
    }
    if (p_stk_data == (OS_STK_DATA *)0) {              /* Validate 'p_stk_data'                        */
        return (OS_ERR_PDATA_NULL);
    }
#endif
    p_stk_data->OSFree = 0;                            /* Assume failure, set to 0 size                */
    p_stk_data->OSUsed = 0;
    OS_ENTER_CRITICAL();
    if (prio == OS_PRIO_SELF) {                        /* See if check for SELF                        */
        prio = OSTCBCur->OSTCBPrio;
    }
    ptcb = OSTCBPrioTbl[prio];
    if (ptcb == (OS_TCB *)0) {                         /* Make sure task exist                         */
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_NOT_EXIST);
    }
    if (ptcb == OS_TCB_RESERVED) {
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_NOT_EXIST);
    }
    if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0) { /* Make sure stack checking option is set       */
        OS_EXIT_CRITICAL();
        return (OS_ERR_TASK_OPT);
    }
    free = 0;
    size = ptcb->OSTCBStkSize;
    pchk = ptcb->OSTCBStkBottom;
    OS_EXIT_CRITICAL();
#if OS_STK_GROWTH == 1
    while (*pchk++ == (OS_STK)0) {                    /* Compute the number of zero entries on the stk */
        free++;
    }
#else
    while (*pchk-- == (OS_STK)0) {
        free++;
    }
#endif
    p_stk_data->OSFree = free * sizeof(OS_STK);           /* Compute number of free bytes on the stack */
    p_stk_data->OSUsed = (size - free) * sizeof(OS_STK);  /* Compute number of bytes used on the stack */
    return (OS_ERR_NONE);
}
#endif
/*$PAGE*/
/*

/*
*********************************************************************************************************
*                                            TASK STACK DATA
*********************************************************************************************************
*/

#if OS_TASK_CREATE_EXT_EN > 0
typedef struct os_stk_data {
    INT32U  OSFree;                    /* Number of free bytes on the stack                            */
    INT32U  OSUsed;                    /* Number of bytes used on the stack                            */
} OS_STK_DATA;
#endif

#if OS_TASK_STAT_EN > 0

void OS_TaskStat (void *p_arg) {……};  //这个就是守护进程

#endif

/*
*********************************************************************************************************
*                                            STATISTICS TASK
*
* Description: This task is internal to uC/OS-II and is used to compute some statistics about the
*              multitasking environment.  Specifically, OS_TaskStat() computes the CPU usage.
*              CPU usage is determined by:
*
*                                          OSIdleCtr
*                 OSCPUUsage = 100 * (1 - ------------)     (units are in %)
*                                         OSIdleCtrMax
*
* Arguments  : parg     this pointer is not used at this time.
*
* Returns    : none
*
* Notes      : 1) This task runs at a priority level higher than the idle task.  In fact, it runs at the
*                 next higher priority, OS_TASK_IDLE_PRIO-1.
*              2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0.
*              3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the
*                 maximum value for the idle counter.
*********************************************************************************************************
*/

#if OS_TASK_STAT_EN > 0
void  OS_TaskStat (void *p_arg)
{
    INT32U     run;
    INT32U     max;
    INT8S      usage;
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif



    p_arg = p_arg;                               /* Prevent compiler warning for not using 'parg'      */
    while (OSStatRdy == OS_FALSE) {
        OSTimeDly(2 * OS_TICKS_PER_SEC / 10);    /* Wait until statistic task is ready                 */
    }
    max = OSIdleCtrMax / 100L;
    for (;;) {
        OS_ENTER_CRITICAL();
        OSIdleCtrRun = OSIdleCtr;                /* Obtain the of the idle counter for the past second */
        run          = OSIdleCtr;
        OSIdleCtr    = 0L;                       /* Reset the idle counter for the next second         */
        OS_EXIT_CRITICAL();
        if (max > 0L) {
            usage = (INT8S)(100L - run / max);
            if (usage >= 0) {                    /* Make sure we don't have a negative percentage      */
                OSCPUUsage = usage;
            } else {
                OSCPUUsage = 0;
            }
        } else {
            OSCPUUsage = 0;
            max        = OSIdleCtrMax / 100L;
        }
        OSTaskStatHook();                        /* Invoke user definable hook                         */
#if (OS_TASK_STAT_STK_CHK_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
        OS_TaskStatStkChk();                     /* Check the stacks for each task                     */
#endif
        OSTimeDly(OS_TICKS_PER_SEC / 10);        /* Accumulate OSIdleCtr for the next 1/10 second      */
    }
}
#endif
/*$PAGE*/

#if OS_TASK_STAT_EN > 0

void OSStatInit (void) {……};  //每一个进程都得调用它

#endif

/*
*********************************************************************************************************
*                                        STATISTICS INITIALIZATION
*
* Description: This function is called by your application to establish CPU usage by first determining
*              how high a 32-bit counter would count to in 1 second if no other tasks were to execute
*              during that time.  CPU usage is then determined by a low priority task which keeps track
*              of this 32-bit counter every second but this time, with other tasks running.  CPU usage is
*              determined by:
*
*                                             OSIdleCtr
*                 CPU Usage (%) = 100 * (1 - ------------)
*                                            OSIdleCtrMax
*
* Arguments  : none
*
* Returns    : none
*********************************************************************************************************
*/

#if OS_TASK_STAT_EN > 0
void  OSStatInit (void)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr = 0;
#endif



    OSTimeDly(2);                                /* Synchronize with clock tick                        */
    OS_ENTER_CRITICAL();
    OSIdleCtr    = 0L;                           /* Clear idle counter                                 */
    OS_EXIT_CRITICAL();
    OSTimeDly(OS_TICKS_PER_SEC / 10);            /* Determine MAX. idle counter value for 1/10 second  */
    OS_ENTER_CRITICAL();
    OSIdleCtrMax = OSIdleCtr;                    /* Store maximum idle counter count in 1/10 second    */
    OSStatRdy    = OS_TRUE;
    OS_EXIT_CRITICAL();
}
#endif
/*$PAGE*/
/*

3.      怎样使用系统API

Task_42 (void *p_arg) {

    error_t error;

    OSStatInit(); //这里应该是CCTV所描写叙述的最美好的天朝。请放我在这里

    while(1) {

        switch(num) { 

             case 42:
                 printf(“42 is the answer to life, the universe, and everything\n”);
                 break;

             ......
             default:
                 break;
        }
    }
}

4.      使用

注意进程控制块的数据结构

/*
*********************************************************************************************************
*                                          TASK CONTROL BLOCK
*********************************************************************************************************
*/

typedef struct os_tcb {
    OS_STK          *OSTCBStkPtr;      /* Pointer to current top of stack                              */

#if OS_TASK_CREATE_EXT_EN > 0
    void            *OSTCBExtPtr;      /* Pointer to user definable data for TCB extension             */
    OS_STK          *OSTCBStkBottom;   /* Pointer to bottom of stack                                   */
    INT32U           OSTCBStkSize;     /* Size of task stack (in number of stack elements)             */
    INT16U           OSTCBOpt;         /* Task options as passed by OSTaskCreateExt()                  */
    INT16U           OSTCBId;          /* Task ID (0..65535)                                           */
#endif

    struct os_tcb   *OSTCBNext;        /* Pointer to next     TCB in the TCB list                      */
    struct os_tcb   *OSTCBPrev;        /* Pointer to previous TCB in the TCB list                      */

#if OS_EVENT_EN	|| (OS_FLAG_EN > 0)
    OS_EVENT        *OSTCBEventPtr;    /* Pointer to event control block                               */
#endif

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
    void            *OSTCBMsg;         /* Message received from OSMboxPost() or OSQPost()              */
#endif

#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
#if OS_TASK_DEL_EN > 0
    OS_FLAG_NODE    *OSTCBFlagNode;    /* Pointer to event flag node                                   */
#endif
    OS_FLAGS         OSTCBFlagsRdy;    /* Event flags that made task ready to run                      */
#endif

    INT16U           OSTCBDly;         /* Nbr ticks to delay task or, timeout waiting for event        */
    INT8U            OSTCBStat;        /* Task      status                                             */
    INT8U            OSTCBStatPend;    /* Task PEND status                                             */
    INT8U            OSTCBPrio;        /* Task priority (0 == highest)                                 */

    INT8U            OSTCBX;           /* Bit position in group  corresponding to task priority        */
    INT8U            OSTCBY;           /* Index into ready table corresponding to task priority        */
#if OS_LOWEST_PRIO <= 63
    INT8U            OSTCBBitX;        /* Bit mask to access bit position in ready table               */
    INT8U            OSTCBBitY;        /* Bit mask to access bit position in ready group               */
#else
    INT16U           OSTCBBitX;        /* Bit mask to access bit position in ready table               */
    INT16U           OSTCBBitY;        /* Bit mask to access bit position in ready group               */
#endif

#if OS_TASK_DEL_EN > 0
    INT8U            OSTCBDelReq;      /* Indicates whether a task needs to delete itself              */
#endif

#if OS_TASK_PROFILE_EN > 0
    INT32U           OSTCBCtxSwCtr;    /* Number of time the task was switched in                      */
    INT32U           OSTCBCyclesTot;   /* Total number of clock cycles the task has been running       */
    INT32U           OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption        */
    OS_STK          *OSTCBStkBase;     /* Pointer to the beginning of the task stack                   *//* 这里是栈基址*/
    INT32U           OSTCBStkUsed;     /* Number of bytes used from the stack                          *//* 这里是使用量*/
#endif

#if OS_TASK_NAME_SIZE > 1
    INT8U            OSTCBTaskName[OS_TASK_NAME_SIZE];
#endif
} OS_TCB;

比如例如以下两个进程的控制块:

1.栈溢出的进程如图1所看到的:

OSTCBStkSize   =  100(100是如果的值,实际值如图所看到的是256)(怎么解决,把该进程OSTCBStkSize设置为大于840/4。比方256 OK)

OSTCBStkUsed  = 840(注意这里单位是char型。所以须要除4之后与OSTCBStkSize比較)

两者的单位都是INT32U型,OSTCBStkUsed > OSTCBStkSize

OMG!!!     StackOverFlow (Id of Mine in stackOverFlow is linpeng1577@gmail.com )

 操作系统栈溢出检測之ucosII篇

                                                                                               图1

2.栈正常的进程如图2所看到的:

注意进程控制块

OSTCBStkSize   = 512

OSTCBStkUsed  = 136(136/4 = 34 < 512)

两者的单位都是INT32U型,OSTCBStkUsed < OSTCBStkSize

OMG!!! StackOverFlow?

 NO! (Id of Mine in stackOverFlow is linpeng1577@gmail.com )

操作系统栈溢出检測之ucosII篇

                                                                                              图2

转载请注明出处,

blog of linpeng1577

谢谢

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/116178.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 系统功能测试用例模板「建议收藏」

    系统功能测试用例模板「建议收藏」系统功能测试用例模板 用例名称 订单支付_银联卡支付_支付银行卡处于欺诈名单当中 用例目录 订单支付/银联卡支付/ 用例编号 Payment037 功能模块 结账支付 优先级别 2 相关需求 《结账支付功能规格说明》 数据准备 余额充足的支付用银联银行卡、已注册的前台用户 前置条件 1.用户已登录 2.用户已将商品加入购物车并触发订单结算流程 3.用户将订单支付流程推进至用银行卡支付节点 步骤 测试

    2022年7月17日
    20
  • 深入浅出Windows BATCH

    深入浅出Windows BATCH

    2021年12月13日
    51
  • db2中You can’t specify target table for update in FROM clause错误

    db2中You can’t specify target table for update in FROM clause错误db2中You can’t specify target table for update in FROM clause错误

    2022年4月23日
    68
  • 2021阿里笔试题

    2021阿里笔试题n个人,初始序号为a[i],当某个人的序号是某个整数的平方时,则获胜。现在发放一定数量的券,每张券可以是自己的序号加一或减一。求让一半的人获胜至少需要多少张券。//testali.cpp:定义控制台应用程序的入口点。//#include”stdafx.h”#include<math.h>#include<iostream>#include<math.h>#include<vector>#include<algori

    2022年5月23日
    44
  • python数据交换模块-XML

    python数据交换模块-XML

    2022年3月11日
    33
  • snmptrap配置_snmp服务端ip和端口

    snmptrap配置_snmp服务端ip和端口一、trap的用途TRAP是提供从代理进程到管理站的异步报告机制。为了使管理站能够及时而又有效地对被管理设备进行监控,同时又不过分增加网络的通信负载,必须使用陷入(TRAP)制导的轮讯过程。代理进程负责在必要时向管理站报告异常事件,得到异常事件的报告后,管理站可以查询有关的代理,以便得到更具体的信息,对事件的原因做进一步的分析二、trap的工作流程1、agent端: A

    2022年8月20日
    26

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号