最近在寫stm32的串口處理程序,遇到一個問題程序跑着跑着就進入了硬件錯誤中斷不可自拔。
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
通過調試定位到錯誤出現在下面的字符串處理函數函數中
char** strsplit(char *str, char stok)
{
char *p = str, *h = str, *item = NULL;
char **ret = NULL, **index;
int size = 0;
while(*p)
{
if(*p == stok)
size++;
p++;
}
ret = (char **)malloc((size+2) * sizeof(char *));
if(ret == NULL)
return NULL;
p = str;
index = ret;
while(*p)
{
if(*p == stok)
{
size = p - h-1;
item = (char *)malloc((size+1)*sizeof(char));
memset(item, '\0', size+1);
if(h == str)
memcpy(item, h,size+1);
else
memcpy(item, h+1,size);
h = p;
*index = item;
index++;
}
p++;
}
size = p - h-1;
item = (char *)malloc(size*sizeof(char));
memcpy(item, h+1,size);
*index = item;
*(index + 1) = NULL;
return ret;
}
這個函數單獨測試沒有任何題,但是我的系統使用的ucos-ii的多線程系統,另外我係統裏還有5個串口中斷處理函數。在這樣的多線程系統中這個函數就出現了問題。
要分析這個函數的問題所在,首先要判斷這回函數是否可重入。這是判斷一個函數是否是線程安全的必要條件。我重讀了這個函數,發現函數中沒有使用全局變量和全局資源,唯一調用了malloc這個函數。如果這函數是不可重入的則strsplit這個函數也是不可重入的。
我百度發現https://blog.csdn.net/weiganyi/article/details/11142347這篇博文說malloc是不可重入的。於是我找到了 問題的原因:
我的程序結構如下:
//中斷處理1
void uart1_hander()
{}
//中斷處理2
void uart2_hander()
{}
//中斷處理3
void uart3_hander()
{}
//中斷處理4
void uart4_hander()
{}
//中斷處理5
void uart5_hander()
{}
//解報文
void thread(){
switch(number){
case 1:
message = strsplit(buff, ',');
break;
case 2:
message = strsplit(buff, ',');
break;
case 3:
message = strsplit(buff, ',');
break;
case 4:
message = strsplit(buff, ',');
break;
case 5:
message = strsplit(buff, ',');
break;
}
}
如果程序在執行strsplit函數中的malloc函數時產生了串口中斷,當中斷返回時就可能出現棧溢出的問題,因此觸發硬件中斷。