一个变量越界引起的灾难

版权声明:本文为博主原创文章,转载请注明出处! https://blog.csdn.net/qq_20553613/article/details/82634350

1.前言
  一般地,对于内存块访问(如数组、程序员动态分配的内存块、系统从堆上分配的内存块),通过“下标”形式访问时,如果稍有不留意,对于末尾地址的访问处理不当,则会发生程序异常,轻则导致当然应用程序(进程)异常退出,重则导致整个系统瘫痪。如果是在嵌入式系统里发生,如裸机程序,或者多线程的实时系统(RTOS)中,基本会导致整个系统程序异常退出(死机)。这对于用户来说是“灾难”性事的、不可接受的。

  对于变量的越界,大多情况下不会导致程序异常,只是业务功能或者底层控制未能达到预期功能。然而,在特殊情况下,依然会导致“灾难”性发生,下面是调用别人代码时发生的一个案例。


2.案例分析
  在此之前未有遇到过类似情况,举此例子的目的不是为了讨伐别人的错误,而是作为自己一个总结和反思,提高自己的编程水平和思维觉悟。源代码不直接上,关键处理函数思路如下。

uint8_t fun_ctrl(uint16_t size)
{
    uint8_t i;

    for(i = 0; i < size;i++)
    {
        /*process*/
    }
    return 0;
}


2.2代码分析
  对于上述函数,存在非常大的问题。入口函数参数是无符号16位数“uint16_t”类型,而函数内部循环变量则为无符号8位数“uint8_t”类型。调用该函数时,如果传入实参变量范围在“uint8_t”内,则完全达到预期功能。但如果,实参变量超出“uint8_t”范围,那么该函数将陷入“死循环”状态,从而导致程序(系统)“假死”,虽然此时系统仍在运行,但当前函数严重占用CPU资源导致其他任务几乎无法执行,而这种情况出现则是“灾难性”的。

  造成的原因,稍加分析比较易发现,因为函数内部计数变量为8位,值范围为0—255,而传入的实参范围超出255,计数变量超出类型现在范围后,则归零,如此往复,陷入死循环。

  在各类应用中,如果调用了上述类似函数,则有几类情况:
1)嵌入式单片机裸机程序中,调用该函数,由于是单一任务执行,其他任务(功能)将永远无法执行,陷入死循环。
2)实时操作系统下,函数被其中一任务线程调用,如果是抢占式内核,并且应用程序采用抢占式调度方式处理,并且该线程是优先级为最高,则其他任何任务无法获取CPU资源,即无法执行相应功能,系统瘫痪。
3)实时操作系统下,函数被其中一任务线程调用,应用程序采用时间片轮询的方式处理,其他任务线程依然能获取CPU资源并执行,但当前任务线程其他功能则无法实现。
4)如果在驱动层,则导致的后果更加不堪设想,并且不易定位bug。
5)如果该函数控制的是相关数据传输,比如串口/CAN向外传输数据,则连接的相关外设也可能因为接收大数据流导致导致严重占用资源甚至异常。

2.1代码改正


3.总结

猜你喜欢

转载自blog.csdn.net/qq_20553613/article/details/82634350