esp32 Stack canary watchpoint срабатывает
Я пишу программу для esp32 на Arduino IDE. В какой-то момент выполнения кода для чтения файла я сталкиваюсь с этим исключением,
Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception)
Debug exception reason: Stack canary watchpoint triggered (loopTask)
Однако, прочитав несколько форумов, я нашел ответ об увеличении глубины стека для вашей задачи FreeRTOS. Мой вопрос: есть ли другой способ справиться с этим исключением, кроме увеличения размера стека и предотвращения сбоя программы?
@Androing, 👍2
1 ответ
Лучший способ справиться с этим исключением - определить, что занимает так много места в стеке, и переписать код, чтобы избежать этого.
Три наиболее распространенных способа использования слишком большого пространства стека:
- большие локальные переменные - например, объявление большого массива в качестве локальной переменной внутри функции, например:
#define VERY_LARGE_STRING_LENGTH 8000
void loop() {
char my_very_large_string[VERY_LARGE_STRING_LENGTH];
for(i = 0; i < VERY_LARGE_STRING_LENGTH; i++)
my_very_large_string[i] = ' ';
}
Локальные переменные хранятся в стеке, поэтому их большой массив будет занимать много места в стеке.
- рекурсивные функции - каждый раз, когда функция рекурсирует, она использует пространство стека. Если он рекурсирует достаточно глубоко, то он растопчет защиту стека и вызовет это исключение. Например:
int count(i) {
i--;
if(i > 0) {
Serial.println(count(i));
}
return i;
}
void loop() {
count(8000);
}
Каждый раз, когда функция рекурсирует, ее обратный адрес, аргументы и локальные переменные сохраняются в стеке. Если он повторяется слишком много раз, он будет использовать больше памяти, чем выделено стеку.
- ошибки в вашем коде, такие как дикие указатели и переполнение буфера
void loop() {
char my_bad_string[10];
char *wild_pointer;
// переполнение буфера
for(i = 0; i < 8000; i++)
my_bad_string[i] = ' ';
// кто знает, где это приведет к указанию
wild_pointer += rand();
wild_pointer = ' ';
}
когда вы переполняете массив в стеке, вы, вероятно, перезаписываете другие переменные и искажаете их значения. Сделайте это достаточно, и вы попадете в охранника стека. Помните, что строки C (массивы символов и указатели) нуждаются
в n + 1
символах для хранения строки длиной n
, потому что они заканчиваются дополнительным нулевым символом '\ 0'
.
Если вы используете рекурсивные функции, посмотрите на способы ограничения рекурсии или использования хвостовой рекурсии, которую компилятор может оптимизировать, чтобы избежать использования чрезмерного пространства стека.
Если вы используете большие переменные, подумайте о том, почему, и перепишите свой код, чтобы иметь возможность использовать меньшие переменные. Например, если вы читаете большой файл, попробуйте обрабатывать его по строчке за раз, а не считывать весь файл в память. Если вы загружаете большой JSON с веб-сервера, попробуйте использовать потоковый парсер JSON, а не загружать его целиком и затем обрабатывать.
Ошибку в вашем коде будет труднее всего выяснить, учитывая, что это ошибка. Будьте осторожны с указателями и распределением памяти. Хотя память выделяется из кучи, а не из стека, если она перезаписана или повторно использована после освобождения, использование ее в качестве указателя все равно может привести к повреждению стека. Также будьте осторожны, чтобы не возвращать указатели на локальные переменные внутри функций:
int *do_not_do_this() {
int this_will_not_work_the_way_you_hope = 0;
return &this_will_not_work_the_way_you_hope;
}
это также может привести к повреждению стека, так как пространство, занимаемое переменной, больше не будет зарезервировано для нее и может быть использовано чем-то другим.
- Adafruit esp32 Feather не удалось скомпилировать
- Передача функции-члена класса в качестве аргумента
- Преобразование byte* в int в Arduino
- ESP32S v1.1 NodeMCU vs ESP32 DevKitV1
- esp32-cam публикует изображение в mqtt
- WindowsError(31, "Устройство, подключенное к системе, не функционирует") в arduino
- Как очистить кучу памяти в esp32
- ESP32 millis не работает должным образом