项目场景:
最近有个案子(MCU:STM32F103VCT6)需要定制个小功能,需要用malloc分配大量的空间。本来是没什么,但是无意中发现,KEIL MDK编译时,malloc分配的空间已经超过预设的大小也不报错。后面发现和自己的使用也有关系。在这边记录一下,给有碰到类似问题的网友们一些参考。
问题描述:
先看启动文件。这里堆分配的大小是0x2000,即8K。
Heap_Size EQU 0x00002000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
在代码里,我创建了一个uint16的数组,数量是4500。所以大小是9000,已经溢出了。
U8 TagGet(void)
{
U8 statue=FALSE;
U16 *pbuf;
U16 cnt,i,j;
U16 const len = 4500;
pbuf = (U16 *)malloc(sizeof(U16)*len);
printf("pbuf = 0x%x\r\n",*pbuf);
if(*pbuf == NULL)
statue=FALSE;
printf("sizeof malloc = %d\r\n",sizeof(U16)*len);
printf("sizeof malloc = 0x%X\r\n\r\n",sizeof(U16)*len);
/* 数组赋值。从0~4500依次按顺序赋值 */
for(i = 0;i<len;i++)
{
pbuf[i] = i;
}
/* 输出数组查看 */
for(i = 0,j = 0;i<len;i=i+5)
{
printf("i = %6d,value = %6d ; ",i,pbuf[i]);
if((j+1)%2==0)
printf("\r\n");
j++;
}
printf("\r\n");
free(pbuf);
pbuf = NULL;
statue=TRUE;
return statue;
}
原以为KEIL MDK会报错,但是实际没有报错。
由于程序里有给数组赋值。从0~4500依次按顺序赋值。根据串口信息发现数组异常,读出的参数全是乱的。
后面才意识到是分配的空间超标了。
所以把分配的数量减小到2000,总数也才4000,在堆的最大限度以内。
编译后,载入再看信息,一切正常。分配的空间可以正常访问。
原因:
由此可见KEIL MDK并不会对malloc分配的空间进行合理的判断,并给出报错。
就算malloc的空间已经超出启动文件里限制的大小,也不会报错。
所以MDK编译阶段,只判断malloc语法的对错,不能分辨堆的申请是否超过预先设定的最大值。资源的分配成功与否,需要我们在代码的逻辑层再做判断。申请失败,则独立处理。
我也发现我的代码处理的也有问题。KEIL MDK虽然在编译阶段不报错,但是在实际运行到malloc时,已经发现空间不足,并给出提示,是我程序对返回值的操作不当,资源分配异常时没有及时处理。
原来的SRC:
if(*pbuf == NULL)
statue=FALSE;
应该改成:
if(pbuf == NULL) {
statue=FALSE;
return statue;
}
地址分配失败直接退出。(这边处理比较简单,实际看个人需求)
小结:
对于malloc,MDK编译阶段,只判断malloc语法的对错,不能分辨堆的申请是否超过预先设定的最大值。虽然在编译阶段不报错,但是在实际运行到malloc时,已经发现空间不足,发现空间不足会返回一个空值,我们自己要在代码里做判断。
(tip:malloc分配成功,会返回分配空间的起始地址;分配失败,返回0。)
所以判断方式都类似,可以直接套用以下处理方式:
pbuf = (U16 *)malloc(sizeof(U16)*len);
if(*pbuf == NULL)
return;