「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战」。
最近在调试一块控制板的时候,程序调试完成测试了两天都正常,突然第三天时,程序一开始运行就出现莫名其妙的错误。折腾了好久都找不到原因,最后单步调试程序时,终于发现是在处理串口接收到的数据时,数组下标没有控制好,导致数据溢出,将内存中的关键数据修改了。从而导致程序运行异常。
下面就将此次踩得坑记录下来,从此要引以为戒,不在犯这种低级错误。
程序主要功能就是从串口接收数据,然后根据数据去执行相应动作。下面直接看调试过程。
程序一开始运行,串口中就接收了一堆数据,然后主程序每隔10ms根据数据长度来判断数据接收是否完成,如果数据接收完成,就将串口缓冲区中的数据拷贝出来,然后进行数据处理。
通过观察内存中的数据发现,一拷贝数据,程序中记录运行状态的变量值就被改变了。而这个状态值又是程序执行的关键参考值,参考值不在数据范围内,从而导致了程序的异常。
那么为什么拷贝数据会导致数据溢出呢?
通过变量观察可以发现,串口数组拷贝的数据大小为11个,但是串口缓存区的大小设置的是10。
查看变量的内存,存放串口数据的数组地址后面紧跟着存放的就是记录程序状态的值。由于数组的大小是10,但是拷贝数据的时候却拷贝了11个,这样刚好将数组后面的变量覆盖了。
通过内存中数据存储情况可以看到,程序将 从20到61的数据拷贝了一份,直接放在了内存中紧跟着的位置,然后又拷贝了一个数据20,又把后面紧跟着的一个数据覆盖了,这个位置又存储着程序状态,从而导致程序一开始接收到的数据就将程序状态改变了,导致程序不能正常执行。
那么为什么拷贝的数据会多了一个呢,仔细检查后,发现了问题所在。
在串口中断函数中,接收数据时有个最大长度限制,这个UART_MAX_NUM值是10,由于数组的下标是从0开始,所以下标最大值只能是9,这里不能使用 <=号来判断,只能使用<号判断。使用=号的话数据计数器就会多计算一个数据,那么在拷贝的时候就会多拷贝一个,从而导致数据溢出。
那么串口中的数据又是哪里来的呢,经过仔细检查后,发现串口的数据线被碰掉了,发送线和接受线挨在了一起,这个接收的数据刚好就是程序开机启动时发出去的数据。
相当于程序一开始执行,向外面发送了一组数据,然后又被自己接收到了,刚好串口接收代码的下标没有控制好,导致系统异常。而平时测试串口时,每组数据的长度都是8个,从而导致没有及时发现这个隐藏的问题。
以后写程序时,一定要注意数组下标的控制,往往都是在这些不经意的小细节上栽跟头。