可能由 strcpy 引起的 HardFault
Posted
技术标签:
【中文标题】可能由 strcpy 引起的 HardFault【英文标题】:HardFault caused probably by strcpy 【发布时间】:2021-01-07 01:39:07 【问题描述】:以下函数在 LPC1769 中运行。我使用 FreeRTOS 版本 10。
我有HardFault
。我已经调试过了,我想我在很长一段时间后解决了这个问题。
如果我运行这个函数,它会给出HardFault
。最初,我怀疑substr3
函数中的malloc
导致了它。释放内存分配没有帮助。因此,我开始逐块注释代码,直到在parseMessage
函数中找到更准确的问题位置。
如果我注释掉 /* START OF PROBLEMATIC AREA */
和 /* END OF PROBLEMATIC AREA */
之间的行
其余代码可以毫无问题地工作。
我在那个代码块中所做的一切,都是在结构变量中赋值。该结构是全局的并已初始化。我相信这些线路最终会导致问题。也许间接地,我不知道那么远。
例如strcpy(productInfoLeft.ucActualID, pid);
如果我运行parseMessage
中的所有代码,它适用于一条或几条消息,它们解析成功,然后 MCU 停止响应。
结构在一个名为common.h
的文件中
struct ProductInfoLeft
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
;
extern struct ProductInfoLeft productInfoLeft;
struct ProductInfoRight
char ucActualID[ 7 ];
char ucProductName[ 13 ];
char ucBestBeforeDate[ 13 ];
char ucPrinted[ 4 ];
char ucToBePrinted[ 4 ];
char ucLane[ 3 ];
char ucLcdNumber [ 2 ];
char ucPrinterLane [ 3 ];
char ucSupplierInfo [ 13 ];
;
extern struct ProductInfoRight productInfoRight;
结构初始化发生在一个名为lcdtasks.c
的文件中;
struct ProductInfoLeft productInfoLeft =
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
;
struct ProductInfoRight productInfoRight =
.ucActualID = "",
.ucProductName = "",
.ucBestBeforeDate = "",
.ucPrinted = "",
.ucToBePrinted = "",
.ucLane = "",
.ucLcdNumber = "",
.ucPrinterLane = "",
.ucSupplierInfo = ""
;
而解析器函数在另一个名为uarttask.c
的文件中;
void parseMessage(char * message)
//Sample data
//const char* str = "7E00002A347C31323030302D3132353330387C33302E30372E323032307C31317C33307C33317C31352D31367C31357C317C57656E67657274880D0000";
// Parsing the frame
char* start;
char* len;
char* cmd;
char* data;
char* chksum;
char* end;
stripEOL(message);
unsigned int messagelen = strlen(message);
start = substr3(message, 0, 2);
len = substr3(message, 2, 4);
cmd = substr3(message, 6, 2);
data = substr3(message, 8, messagelen-8-4);
chksum = substr3(message, messagelen-4, 2);
end = substr3(message, messagelen-2, 2);
// Converting hex (only for data) to string
char str[250];
hex_to_string(data, str, sizeof(str));
// Parsing the data in variables
//Sample data content to be parsed in variables;
//char str1[50] ="7|10000-145310|12.10.2018|1|10|0|15-16|15|1|Wegert";
char pid[6], pname[12], bbdate[10], pnr[2], ltoprinted[3], lprinted[3], planes[5], laneNr[2], lcdNr[1], sinfo[12];
strcpy(pid, strtok(str , "|"));
strcpy(pname, strtok(NULL , "|"));
strcpy(bbdate, strtok(NULL, "|"));
strcpy(pnr , strtok(NULL, "|"));
strcpy(ltoprinted , strtok(NULL, "|"));
strcpy(lprinted, strtok(NULL, "|"));
strcpy(planes, strtok(NULL, "|"));
strcpy(laneNr, strtok(NULL, "|"));
strcpy(lcdNr, strtok(NULL, "|"));
strcpy(sinfo, strtok(NULL, "|"));
uint8_t resultLCDNr1 = strncmp(lcdNr, "1", 1);
uint8_t resultLCDNr2 = strncmp(lcdNr, "2", 1);
uint8_t result7E = strcmp(start, pcStart);
uint8_t result0D = strcmp(end, pcEnd);
uint8_t result2A = strcmp(cmd, pcProductChange);
uint8_t result30 = strcmp(cmd, pcSupplierChange);
char planeleft[2], planeright[2], tempplanes[5];
strcpy(tempplanes, planes); // If this is used, the next strcpy causes lprinted variable's first element to be "0\"
strcpy(planeleft, strtok(tempplanes , "-"));
strcpy(planeright, strtok(NULL , "-"));
/* START OF PROBLEMATIC AREA */
if (result7E == 0 && result0D == 0)
if (result2A == 0) //Product Change
if (resultLCDNr1 == 0)
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
else if (resultLCDNr2 == 0)
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
else
return;
SetProductChangeOnLCD(lcdNr);
if (result30 == 0) //Supply Change
if (resultLCDNr1 == 0)
strcpy(productInfoLeft.ucActualID, pid);
strcpy(productInfoLeft.ucPrinterLane, planeleft);
strcpy(productInfoLeft.ucProductName, pname);
strcpy(productInfoLeft.ucBestBeforeDate, bbdate);
strcpy(productInfoLeft.ucPrinted, lprinted);
strcpy(productInfoLeft.ucToBePrinted, ltoprinted);
strcpy(productInfoLeft.ucLane, laneNr);
strcpy(productInfoLeft.ucLcdNumber, lcdNr);
strcpy(productInfoLeft.ucSupplierInfo, sinfo);
else if (resultLCDNr2 == 0)
strcpy(productInfoRight.ucActualID, pid);
strcpy(productInfoRight.ucPrinterLane, planeright);
strcpy(productInfoRight.ucProductName, pname);
strcpy(productInfoRight.ucBestBeforeDate, bbdate);
strcpy(productInfoRight.ucPrinted, lprinted);
strcpy(productInfoRight.ucToBePrinted, ltoprinted);
strcpy(productInfoRight.ucLane, laneNr);
strcpy(productInfoRight.ucLcdNumber, lcdNr);
strcpy(productInfoRight.ucSupplierInfo, sinfo);
else
return;
SetSupplierChangeOnLCD(lcdNr);
/* END OF PROBLEMATIC AREA */
free(start);
free(len);
free(cmd);
free(data);
free(chksum);
free(end);
子串函数:
char *substr3(char const *input, size_t start, size_t len)
char *ret = malloc(len+1);
memcpy(ret, input+start, len);
ret[len] = '\0';
return ret;
【问题讨论】:
数据是什么样的? NTW:请给我们看看 substr() 函数。 不是sizeof
。您需要使用strlen
。并且强烈建议不要保持当前代码不变。它充满了缓冲区溢出漏洞。输入意外的输入会在内存中炸出一个洞。
@user3121023,因为,我还要为\0
留一个空间?
@user3121023,确实,还有更多。但是,这只是错误的样本。这是正确的样本; char str1[50] ="7|10000-145310|12.10.2018|1|10|0|15-16|15|1|Wegert";
@Sener 在您的示例字符串中,第二个标记 10000-145310
有 12 个字符。计算 nul 终止符 strcpy(pname, strtok(NULL , "|"));
将超出分配的 char pname[12];
。
【参考方案1】:
仅供参考,我想分享我的发现和问题的解决方案。
有两个问题。一个是数组大小,其中 char 用于 strcpy。没有像一些贡献者提到的那样正确设置。
一旦数组大小固定,另一个问题就会以更清晰的方式暴露出来。这是关于malloc的。出于某种原因,尽管在各种资源中有些评论另有说明,但如果您在 FreeRTOS 实现中使用 malloc,您可能会遇到 HardFault。一旦我切换到 FreeRTOS 建议的 malloc 和 free 函数,事情就变得平淡了。 HardFault 问题神奇地消失了。
我刚刚放置了这两个包装函数(在一个公共文件中的某个位置),甚至没有更改我的 malloc 和 free 调用。;
创建与内置 FreeRTOS 堆一起使用的 malloc/free 函数非常简单。我们只是包装 pvPortMalloc/pvPortFree 调用:
void* malloc(size_t size)
void* ptr = NULL;
if(size > 0)
// We simply wrap the FreeRTOS call into a standard form
ptr = pvPortMalloc(size);
// else NULL if there was an error
return ptr;
void free(void* ptr)
if(ptr)
// We simply wrap the FreeRTOS call into a standard form
vPortFree(ptr);
请注意:您不能将其与堆模式 #1 一起使用,但与其他模式(2、3、4 和 5)一起使用。我建议开始使用portable/MemMang/heap_4.c
【讨论】:
以上是关于可能由 strcpy 引起的 HardFault的主要内容,如果未能解决你的问题,请参考以下文章