Доступ к неверному ключу в ArduinoJson приводит к перезагрузке ESP32
Я работаю над проектом, в котором несколько плат ESP32 взаимодействуют через WebSockets. Для этого я использую Arduino IDE 2.3.4. В основном, обмен данными осуществляется через JSON, данные передаются в виде строк. Для работы с JSON в моём коде на C++ я использую ArduinoJson 7.3.0.
При попытке присвоить значение некоторому ключу в JsonDocument переменной, если ключ не существует, должно возвращаться значение по умолчанию.
JsonVariant::as<T>():
JsonVariant::as<T>()возвращает значение, на которое указываетJsonVariant, приведенный к указанному типу.Эта функция возвращает значение по умолчанию, если приведение типа невозможно. Значение по умолчанию:
0для числовых типовNULLдляconst char*- Пустая ссылка для
JsonArrayиJsonObject.
В цитате не упоминаются строковые типы, но я бы предположил, что это будет выглядеть так, будто класс string инициализируется пустой строкой. Похоже, это справедливо для std::string_view и ArduinoJsons JsonString. std::string имеет значение "null", что тоже приемлемо.
Однако использование Arduino String не работает. Каким-то образом возникает исключение, которое приводит к перезагрузке ESP32. Использование обработчика событий, чтобы хотя бы предотвратить перезагрузку ESP32, тоже не работает.
Ниже приведен пример кода для тестирования и полученный результат.
#include <ArduinoJson.h>
#include <string_view>
#include <string>
template <typename T>
void print(const T& t) {
const char* str = "(empty)";
if constexpr (std::is_same_v<T, const char*>) {
str = t ? t : str;
} else if constexpr (std::is_same_v<T, String>) {
str = t.length() ? t.c_str() : str;
} else if constexpr (std::is_same_v<T, std::string_view>) {
str = !t.empty() ? t.data() : str;
} else {
str = t.size() ? t.c_str() : str;
}
Serial.print(str);
}
template <typename T>
void testImpl(const char* name, JsonDocument& doc) {
Serial.printf("Testing type %s\n", name);
delay(1'000);
JsonVariant v = doc.as<JsonVariant>();
T val = v["key"].as<T>();
print(val);
Serial.println("\t> worked fine!");
delay(1'000);
}
void setup() {
Serial.begin(115'200);
}
void loop() {
Serial.println("Testing access of invalid key with different string types");
JsonDocument doc;
const DeserializationError error = deserializeJson(doc, "{\"foo\":0}");
if (error) {
Serial.printf("deserializeJson() failed: %s\n", error.c_str());
} else {
#define TEST(T) testImpl<T>(#T, doc)
TEST(const char*);
TEST(std::string_view);
TEST(std::string);
TEST(JsonString);
TEST(String);
}
}
Testing access of invalid key with different string types
Testing type const char*
(empty) > worked fine!
Testing type std::string_view
(empty) > worked fine!
Testing type std::string
null > worked fine!
Testing type JsonString
(empty) > worked fine!
Testing type String
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400861c9 PS : 0x00060730 A0 : 0x800d3c91 A1 : 0x3ffb2050
A2 : 0x00000000 A3 : 0xfffffffc A4 : 0x000000ff A5 : 0x0000ff00
A6 : 0x00ff0000 A7 : 0xff000000 A8 : 0x00000000 A9 : 0x3ffb2020
A10 : 0x3ffb20ac A11 : 0x00000000 A12 : 0x00000000 A13 : 0x00000000
A14 : 0x3ffc2190 A15 : 0x3ffb20ac SAR : 0x0000001b EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x400861c9 LEND : 0x400861d9 LCOUNT : 0xffffffff
Backtrace: 0x400861c6:0x3ffb2050 0x400d3c8e:0x3ffb2060 0x400d2985:0x3ffb2080 0x400d3451:0x3ffb21b0 0x400d4f8c:0x3ffb2270 0x40088c51:0x3ffb2290
Мне интересно, является ли результат доступа к недопустимому ключу просто неопределенным, я делаю что-то неправильно или это может быть ошибка в библиотеке ArduinoJson или где-то еще.
Я знаю, что мог бы сначала проверить, существует ли он, или использовать const char* и проверить, является ли он nullptr, но это просто добавляет дополнительные шаги.
@Joel, 👍0
Обсуждение1 ответ
Лучший ответ:
Похоже, это одна из недавних проблем с классом String в ядре Arduino для ESP32.
Пожалуйста, проверьте:
- Сбой при использовании String::move для пустой строки #10938
- Сбой в serializeJson с пустыми значениями после обновления № 10971
- Каков наилучший способ преобразования std::string в строку?
- Не могу скомпилировать .ino с помощью библиотеки ArduinoJson
- Не могу прочитать данные json esp 32 ошибка «parseObject() failed»
- Создание форматированной строки (включая числа с плавающей запятой) в Arduino-совместимом C++
- Arduino Преобразование std:string в String
- Как преобразовать форматированный оператор print в строковую переменную?
- Преобразование строки в IP-адрес
- esp32 Stack canary watchpoint срабатывает
Вы также можете использовать containsKey... Но, как правило, при работе с указателями необходимо учитывать nullptr. Или использовать исключения, если они включены., @KIIV
Это не воспроизводится здесь на ESP32-S3 под управлением ESP32 Arduino core v3.1.1 и ArduinoJson v7.3.0, @timemage
@timemage Удивительно, но тот же самый код с той же версией Arduino IDE, ядром ESP32 и ArduinoJson, даже с тем же ESP32, не выдал ошибку при загрузке скетча с моего ноутбука., @Joel