HardFault可能是由strcpy引起的

问题描述

以下功能在LPC1769中运行。我使用FreeRTOS版本10。 我有HardFault。我已经调试,长时间工作后我想解决这个问题。

如果我运行此函数,它将给出HardFault。最初,我怀疑malloc函数中的substr3导致了它。释放内存分配没有帮助。因此,我开始逐块注释掉代码,直到在parseMessage函数中找到问题的更准确位置为止。

如果我注释掉/* START OF PROBLEMATIC AREA *//* END OF PROBLEMATIC AREA */间的界限 其余代码无需打h即可工作。

我在该代码块中所做的所有事情,都是在struct变量中分配值。该结构是全局的并已初始化。我认为,这最终会导致问题。也许是间接的,我还不知道。

例如strcpy(productInfoLeft.ucActualID,pid);

如果我运行parseMessage中的所有代码,则它适用于一条或几条消息,它们解析为OK,然后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 = "",.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,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,"|"));
        strcpy(pnr,"|"));
        strcpy(ltoprinted,"|"));
        strcpy(lprinted,"|"));
        strcpy(planes,"|"));
        strcpy(laneNr,"|"));
        strcpy(lcdNr,"|"));
        strcpy(sinfo,"|"));
     
        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,"-"));  
     
/* 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,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;
}

解决方法

仅供参考,我想分享我的发现和解决问题的方法。

有两个问题。一种是数组大小,其中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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...