Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passing JsonDocument by reference #2088

Closed
jgroszko opened this issue May 7, 2024 · 4 comments
Closed

Passing JsonDocument by reference #2088

jgroszko opened this issue May 7, 2024 · 4 comments
Labels

Comments

@jgroszko
Copy link

jgroszko commented May 7, 2024

Describe the issue
I'm trying to DRY up my code and create a helper function for fetching some JSON and filtering it, but it looks like my program is crashing when it returns from the helper function.

Troubleshooter report
Here is the report generated by the ArduinoJson Troubleshooter:

  1. The program uses ArduinoJson 7
  2. The issue happens at run time
  3. The issue concerns deserialization
  4. deserializeJson() returns Ok
  5. Program crashes
  6. The program crashes when reading a value from the JsonDocument
  7. Replacing pointer with a String doesn't solve the issue
  8. Program calls neither strcmp(), nor strcpy(), not printf()

Environment
Here is the environment that I'm using':

  • Microconroller: ESP32-D0WD-V3
  • IDE: Arduino IDE 2.3.2

Reproduction
Here is a small snippet that demonstrate the problem.

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid = "...";
const char* password = "...";

bool filteredJsonGet(String &url, JsonDocument &result, JsonDocument &filter) {
  HTTPClient http;
  http.useHTTP10(true);
  http.begin(url);
  Serial.println("About to get");
  int httpCode = http.GET();
  Serial.println("Got");

  if(httpCode != 200) {
    Serial.print("GET failed ");
    Serial.print(httpCode);
    Serial.print(" - ");
    Serial.println(url);

    http.end();

    return false;
  } else {
    Serial.println("HTTP Success");
    DeserializationError error = deserializeJson(result, http.getStream(), DeserializationOption::Filter(filter));
    Serial.println("Deserialized json");

    http.end();

    if (error) {
      Serial.print("GET failed ");
      Serial.print(url);
      Serial.print(" - deserializeJson() failed: ");
      Serial.println(error.c_str());
      return false;
    }

    if (result.overflowed()) {
      Serial.print("GET failed ");
      Serial.print(url);
      Serial.println(" - Ran out of memory for JsonDocument");
      return false;
    }

    Serial.println("No json errors");
  }
}

void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  String url = "http://worldtimeapi.org/api/timezone/America/Chicago";

  JsonDocument filter;
  filter["unixtime"] = true;

  JsonDocument result;

  if(filteredJsonGet(url, result, filter)) {
    Serial.print("Success ");
    Serial.println(result["unixtime"].as<const char*>());
  } else {
    Serial.println("Fail");
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Program output
If relevant, include the program output.

Expected output:

About to get
Got
HTTP Success
Deserialized json
No json errors
Success - 123456

Actual output:

About to get
Got
HTTP Success
Deserialized json
No json errors

abort() was called at PC 0x4015775e on core 1

Backtrace: 0x400838bd:0x3ffb2040 0x4008ec51:0x3ffb2060 0x40093fc9:0x3ffb2080 0x4015775e:0x3ffb2100 0x400d6355:0x3ffb21a0 0x400dde3e:0x3ffb2290

ELF file SHA256: 7b27522cbd92f4eb

Decoding stack results
0x400838bd: panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:408
0x4008ec51: esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:137
0x40093fc9: abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/abort.c:46
0x4015775e: _Unwind_Resume at /Users/brnomac003/.gitlab-runner/builds/qR2TxTby/0/idf/crosstool-NG/.build/xtensa-esp32-elf/src/gcc/libgcc/unwind.inc:245
0x400d6355: setup() at /Users/john/Documents/Arduino/arduinojson_pass_by_reference/arduinojson_pass_by_reference.ino:59
0x400dde3e: loopTask(void*) at /Users/john/Library/Arduino15/packages/Inkplate_Boards/hardware/esp32/8.1.0/cores/esp32/main.cpp:42

Thanks!

@jgroszko jgroszko changed the title Passing ArduinoJson by reference Passing JsonDocument by reference May 7, 2024
@bblanchon
Copy link
Owner

Hi @jgroszko,

After making the following changes, I could successfully run your program on my ESP32.

  #include <WiFi.h>
  #include <HTTPClient.h>
  #include <ArduinoJson.h>
  
  const char* ssid = "...";
  const char* password = "...";
  
  bool filteredJsonGet(String &url, JsonDocument &result, JsonDocument &filter) {
    HTTPClient http;
    http.useHTTP10(true);
    http.begin(url);
    Serial.println("About to get");
    int httpCode = http.GET();
    Serial.println("Got");
  
    if(httpCode != 200) {
      Serial.print("GET failed ");
      Serial.print(httpCode);
      Serial.print(" - ");
      Serial.println(url);
  
      http.end();
  
      return false;
    } else {
      Serial.println("HTTP Success");
      DeserializationError error = deserializeJson(result, http.getStream(), DeserializationOption::Filter(filter));
      Serial.println("Deserialized json");
  
      http.end();
  
      if (error) {
        Serial.print("GET failed ");
        Serial.print(url);
        Serial.print(" - deserializeJson() failed: ");
        Serial.println(error.c_str());
        return false;
      }
  
      if (result.overflowed()) {
        Serial.print("GET failed ");
        Serial.print(url);
        Serial.println(" - Ran out of memory for JsonDocument");
        return false;
      }
  
      Serial.println("No json errors");
    }

+   return true;    
  }
  
  void setup() {
    Serial.begin(115200);
    
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
    }
  
    String url = "http://worldtimeapi.org/api/timezone/America/Chicago";
  
    JsonDocument filter;
    filter["unixtime"] = true;
  
    JsonDocument result;
  
    if(filteredJsonGet(url, result, filter)) {
      Serial.print("Success ");
-     Serial.println(result["unixtime"].as<const char*>());
+     Serial.println(result["unixtime"].as<unsigned long>());
    } else {
      Serial.println("Fail");
    }
  }
  
  void loop() {
    // put your main code here, to run repeatedly:
  
  }

I tested with versions 2.0.14 and 2.0.16 of the Arduino Core for ESP32.

I first thought that the crash was due to calling Serial.println() with a null string, but after checking with the implementation, I confirmed that it is safe to pass a null char pointer. Besides, the original code was not crashing my device; it just didn't write anything after Success .

Best regards,
Benoit

@bblanchon
Copy link
Owner

PS: I just saw in your crash dump that you are using the Inkplate core. I looked at the source code and found the same protection against null pointers passed to println().

@jgroszko
Copy link
Author

jgroszko commented May 8, 2024

Hey Benoit,

Thanks for the quick response! It was definitely the missing return statement, glad it was something simple. I was afraid it'd be some pointer nonsense that I was missing.

@jgroszko jgroszko closed this as completed May 8, 2024
@bblanchon
Copy link
Owner

You're welcome, @jgroszko.
Thank you for using ArduinoJson!
Don't forget to cast a star to support the project 😉

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants