Предотвратить переполнение массива символов в c - PullRequest
0 голосов
/ 21 февраля 2019

Я разрабатываю прошивку для ESP32, используя ESP-IDF и FreeRTOS.Я хочу преобразовать показание датчика в массив символов и сохранить его в энергонезависимой памяти.Когда берется новое чтение, оно должно быть добавлено в начало массива char, выдвигая более старые показания вправо.

Я делаю манипуляции с массивом следующим образом:

#define MAX_BYTES 100
char oldData[MAX_BYTES];
nvs_get_str( nvsHandle, MASS_STRING_STORE, newData, &required_size);
char newData[15];
sprintf(newData, "%2.2f", Totalmass);
strcat(newData, ",");
printf("new data: %s\n", newData);
printf("strlen oldData: %d\n", strlen(oldData));
printf("strlen newData: %d\n", strlen(newData));
printf("sizeof oldData: %d\n", sizeof(oldData));
printf("i starts from: %d\n", (sizeof(oldData)-strlen(newData2)-1));
for(int i = (sizeof(oldData)-strlen(newData) - 1); i >= 0; i--)
{
    oldData [i + strlen( newData )] = oldData[i];
}
for(int i = 0; i < ( strlen(newData) ); i++)
{
    oldData[i] = newData[i];
}
nvs_set_str(nvsHandle, MASS_STRING_STORE, oldData);

Теперь перейдем к проблеме, с которой я столкнулся:

Код вылетает, как только длина строки превышает MAX_LENGTH, т. Е. 100.
Сообщение об ошибке:

"ГуруОшибка медитации: Ядро 0 запаниковало (прерывание wdt на CPU0) "

После сброса сбоя код продолжает работать нормально, пока не произойдет сбой снова.Strlen of oldData печатает 104 и остается на 104 (я думаю, максимум должен быть 99?).Сбой кода происходит точно после завершения одного полного цикла бесконечного цикла задачи.

Может кто-нибудь подсказать мне, что я могу здесь делать неправильно?Я могу предоставить больше информации, если это необходимо.

Заранее спасибо!

РЕДАКТИРОВАТЬ:

Получается, что следующая строка не закомментирована:

strcpy(NEWDATA, oldData);

где NEWDATA - это массив размером 20, который явно переполнен и, следовательно, вызывает вышеуказанную проблему, которая теперь решена.Другая проблема, с которой я сейчас сталкиваюсь, заключается в том, что копия моего текущего чтения прикрепляется к концу массива.Ниже я приложил копию моих журналов:

new data: 5.00,
strlen oldData: 105
strlen newData: 5

Final Data: 5.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5.00,

Для MAX_LENGTH 100, мой массив имеет размер 105 и остается больше 100 в зависимости от длины моего нового чтения.Тем не менее, мой код не падает.Но дополнительные 5 моих окончательных данных - это всегда текущее значение, которое я получаю.Кто-нибудь может мне помочь с этим?

Ответы [ 4 ]

0 голосов
/ 22 февраля 2019

Добавление второго ответа из-за редактирования OP.

Прежде всего, желательно показать рабочий код.Этот отрывок предполагает, что это не скомпилируется:

nvs_get_str( nvsHandle, MASS_STRING_STORE, newData, &required_size);
char newData[15];

По поводу вашего вопроса: ваш вывод printf () заставляет меня задаться вопросом, действительно ли вы работаете с строковыми данными здесь.Если это не так, вы не хотите использовать nvs_get_str (), так как он прекратит чтение NVS после того, как встретит нулевой символ.Точно так же strlen () может работать некорректно, если вы используете его для нестроковых данных.

Если вы храните и манипулируете нестроковыми данными, используйте nvs_get_blob (), чтобы получить их, и функции памяти дляскопировать его в вашу программу.

0 голосов
/ 21 февраля 2019

Вы делаете копию newData в oldData.strlen () возвращает длину newData , исключая нулевой терминатор.Таким образом, ваш результирующий массив символов может быть неопределенным, что вызовет вызов nvs_set_str () для выполнения нежелательных действий, а также займет достаточно времени для запуска WDT.

Кроме того, ваш побайтовый сдвиг oldData МОЖЕТ бытьускорился благодаря memcpy ().Я сказал бы, потому что я не уверен, что memcpy работает правильно при замене in situ ;вам нужно прочитать документы по этому вопросу.

0 голосов
/ 22 февраля 2019

Все комментарии и ответы высоко ценятся, и я буду учитывать все мнения, чтобы сделать мой код лучше.

Однако оказалось, что я ошибочно раскомментировал строку в своем коде, где находился мой последний массивскопированы в меньший массив.Вот почему мой код продолжал падать.Проблема на данный момент решена.Я займусь потреблением времени и оптимизацией этого кода позже, как только я закончу реализацию других функций моего кода.

Спасибо всем !!

0 голосов
/ 21 февраля 2019

«Прерывание wdt прерывания на CPU0» совершенно ясно.Вы сбросили тайм-аут сторожевого таймера.Что, в свою очередь, означает, что ваш код слишком медленный или вы не пинаете собаку из любого места в вашем коде.

Использование stdio.h во встраиваемых системах - это в значительной степени нет-нет, так как это чрезвычайномедленный и ресурсоемкий.

Другой пример, если оптимизация плохая или отключена, for(int i = 0; i < ( strlen(newData) ); i++) может дать очень медленный код, который следует заменить на size_t length = strlen(newData); for(int i=0; i<length; ...

И, наконец, если вы пишетечтобы начать мигать, драйвер должен сначала стереть вспышку, что занимает очень много времени.

...