Жесткий сбой, вызванный, вероятно, strcpy

#c #freertos #lpc

#c #freertos #lpc

Вопрос:

Приведенная ниже функция выполняется в LPC1769. Я использую FreeRTOS версии 10. У меня есть HardFault . Я отладил, и я думаю, что загнал проблему в угол после долгих часов.

Если я запускаю эту функцию, она выдает HardFault . Изначально я подозревал malloc substr3 , что это вызвано функцией. Освобождение выделенной памяти не помогло. Поэтому я начал комментировать код блок за блоком, пока не найду более точное местоположение проблемы в 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 amp;amp; 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]  = '';
    return ret;
}
  

Комментарии:

1. И как выглядят данные? NTW: покажите нам функцию substr(), тоже, пожалуйста.

2. Нет sizeof . Вам нужно использовать strlen . И настоятельно рекомендовал бы не сохранять текущий код как есть. Он полон уязвимостей, использующих переполнение буфера. Подача неожиданных входных данных приведет к пробоинам по всей памяти.

3. @user3121023, потому что мне нужно оставить еще одно место для ?

4. @user3121023, действительно, их больше. Но это просто неправильный образец. Это правильный; char str1[50] ="7|10000-145310|12.10.2018|1|10|0|15-16|15|1|Wegert";

5. @Sener В вашей строке примера 2-й токен 10000-145310 содержит 12 символов. Подсчет нулевого терминатора strcpy(pname, strtok(NULL , "|")); приведет к переполнению выделенного char pname[12]; .

Ответ №1:

Просто для дальнейшего использования, я хотел бы поделиться своими выводами и решением проблем.

Было две проблемы. Одним из них были размеры массива с символом, используемым для strcpy. Не были установлены должным образом, как упоминали некоторые участники.

Как только эти размеры массива были исправлены, другая проблема проявилась более четко. Речь шла о malloc. По какой-то причине, хотя некоторые замечания говорят об обратном в различных ресурсах, если вы используете malloc в реализации FreeRTOS, есть вероятность, что у вас может быть HardFault. Как только я переключился на FreeRTOS, предложив функции malloc и free, все выровнялось. Проблема с HardFault волшебным образом исчезла.

Я только что разместил эти две функции-оболочки (где-то в общем файле), даже не изменив мои malloc и бесплатные вызовы.;

Создание функций malloc / free, которые работают со встроенной кучей FreeRTOS, довольно просто. Мы просто завершаем вызовы 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