Search code examples
cfreertoslpc

HardFault caused probably by strcpy


The function below runs in LPC1769. I use FreeRTOS version 10. I am having HardFault. I have debugged and I think I cornered the issue after long hours.

If I run this function it gives HardFault. Initially, I suspected malloc in substr3 function causes it. Freeing memory allocations didn't help. I therefore started to comment-out the code block by block until I find more accurate location of the issue in the parseMessage function.

If I comment out the lines between /* START OF PROBLEMATIC AREA */ and /* END OF PROBLEMATIC AREA */ the rest of code works without a single hiccup.

All I do in that code block, I assign values in the struct variables. The struct is global and initialized. I believe that that lines are causing the issue eventually. Maybe indirectly, I don't know that far.

e.g. strcpy(productInfoLeft.ucActualID, pid);

If I run all the codes in the parseMessage, it works for one or a few messages, they parsed OK and then MCU stops responding.

Struct in a file called 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;

Struct initialization takes place in a file called 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 = ""
};

And the parser function in another file called 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); 
    }

Substring function:

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;
}

Solution

  • Just for future reference, I like to share my findings and resolution of the problems.

    There were two issues. One was array sizes with char used for strcpy. There were not properly set as some contributors mentioned.

    Once that array sizes fixed, another issue was revealed itself in a clearer manner. It was about the malloc. For some reason although some remarks say otherwise in various resources, if you use malloc within FreeRTOS implementation, there is a chance you might have HardFault. Once I switched to FreeRTOS suggested malloc and free functions, things flattened. HardFault issue magically disappeared.

    I've just placed that two wrapper functions (somewhere in a common file) without even changing my malloc and free calls.;

    Creating a malloc/free functions that work with the built-in FreeRTOS heap is quite simple. We just wrap the pvPortMalloc/pvPortFree calls:

    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);
        }
    }
    

    Note that: You can't use that with heap schema #1 but with the others (2, 3, 4 and 5). I would recommend start using portable/MemMang/heap_4.c