DaveGamble / cJSON

Ultralightweight JSON parser in ANSI C
MIT License
10.87k stars 3.22k forks source link

cJSON_Print results null output string when json is too long #458

Open our30K opened 4 years ago

our30K commented 4 years ago

Hi there

I storing three PKI certificate strings in the json, but when using cJSON_Print to print out the result string, it returns nothing. if I reduce to one certificate string, it works.
below are the code. size is integer, name is just the name of the cert, for example: ca_cert the actual cert or key are string of about 1200-1800bytes each. so total about 5000 bytes

any idea how to fix this? I rather not to split these information into 3 JSON and print separately

 cJSON *certvars = cJSON_CreateObject();

// first cert .......
  if (cJSON_AddNumberToObject(certvars, "ca_size", cacrt_info.size)== NULL){
      Serial.println("ca_size failed");
  }
  if (cJSON_AddStringToObject(certvars, "ca_name", cacrt_info.name.c_str())== NULL){
      Serial.println("ca_name failed");
  }
   if (cJSON_AddStringToObject(certvars, "ca_cert", cacrt_info.crt.c_str())== NULL){
       Serial.println("ca_certfailed");
   }

// 2nd cert .......
  if (cJSON_AddNumberToObject(certvars, "ca_size2", cacrt_info.size)== NULL){
      Serial.println("ca_size failed");
  }
  if (cJSON_AddStringToObject(certvars, "ca_name2", cacrt_info.name.c_str())== NULL){
      Serial.println("ca_name failed");
  }
   if (cJSON_AddStringToObject(certvars, "ca_cert2", cacrt_info.crt.c_str())== NULL){
       Serial.println("ca_certfailed");
   }

// 3rd cert .......
  if (cJSON_AddNumberToObject(certvars, "ca_size3", cacrt_info.size)== NULL){
      Serial.println("ca_size failed");
  }
  if (cJSON_AddStringToObject(certvars, "ca_name3", cacrt_info.name.c_str())== NULL){
      Serial.println("ca_name failed");
  }
   if (cJSON_AddStringToObject(certvars, "ca_cert3", cacrt_info.crt.c_str())== NULL){
       Serial.println("ca_certfailed");
   }

  String file_str = cJSON_Print(certvars);
  if (file_str == NULL)
    {
        fprintf(stderr, "Failed to print.\n");
    }
our30K commented 4 years ago

I tried using


cJSON_bool format = true;
String file_str = cJSON_PrintBuffered(certvars,5000,format);  

does not seem to work either

Alanscut commented 4 years ago

Are you running it on an embeded system? I think you'r better adjust your available heap memory. Or try to use cJSON_AddItemReferenceToObject and cJSON_CreateStringReference, this API will not alloct new memory for valuestring:

cJSON_AddItemReferenceToObject(certvars, "ca_cert", cJSON_CreateStringReference(cacrt_info.crt.c_str()))== NULL
Alanscut commented 4 years ago

All your ca_cert string could be added to certvars, so your heap memory could store total about 5000 bytes, after reducing this part memory, I think it should work.

our30K commented 4 years ago

Hi Alanscut

thanks for the quick answer on this, I tried using cJSON_CreateStringReference it did not work.

here are the updated full function code,


  cJSON *certvars = cJSON_CreateObject();

// adding basic info
  if (cJSON_AddNumberToObject(certvars, "ca_size", cacrt_info.size)== NULL){
      Serial.println("ca_size failed");
  }
  if (cJSON_AddStringToObject(certvars, "ca_name", cacrt_info.name.c_str())== NULL){
      Serial.println("ca_name failed");
  }
  if (cJSON_AddNumberToObject(certvars, "key_size", kycrt_info.size)== NULL){
      Serial.println("key_size failed");
  }
  if (cJSON_AddStringToObject(certvars, "key_name", kycrt_info.name.c_str())== NULL){
      Serial.println("key_name failed");
  }
  if (cJSON_AddNumberToObject(certvars, "cc_size", cccrt_info.size)== NULL){
      Serial.println("cc_size failed");
  }
  if (cJSON_AddStringToObject(certvars, "cc_name", cccrt_info.name.c_str())== NULL){
      Serial.println("cc_name failed");
  }

  Serial.println(String(ESP.getFreeHeap()));

//adding reference to certificate strings
  cJSON *ca_cert = NULL;
  ca_cert = cJSON_CreateStringReference(cacrt_info.crt.c_str());
    if (ca_cert == NULL)
    {
       Serial.println("cacrt_info failed");
    }
  cJSON_AddItemReferenceToObject(certvars, "ca_cert", ca_cert);

  cJSON *client_key = NULL;
  client_key = cJSON_CreateStringReference(kycrt_info.crt.c_str());
  if (client_key == NULL)
  {
    Serial.println("kycrt_info failed");
  }
  cJSON_AddItemReferenceToObject(certvars, "client_key", client_key);

  cJSON *cc_cert = NULL;
  cc_cert = cJSON_CreateStringReference(cccrt_info.crt.c_str());
  if (cc_cert == NULL)
  {
     Serial.println("cccrt_info failed");
  }
  cJSON_AddItemReferenceToObject(certvars, "cc_cert", cc_cert);

  Serial.println(String(ESP.getFreeHeap()));
  String file_str = cJSON_Print(certvars);
  if (file_str == NULL)
   {
       fprintf(stderr, "Failed to print.\n");
   }

the heap memory before and after adding the three certs are 36300 vs 35612 the heap info is obtained via ESP.getFreeHeap(). the code is running in ESP32.

so it seems may not be the heap issue ? since heap memory is abundent ?

need more ideas :)

thanks

our30K commented 4 years ago

Hi guys,

I still could not solve the above issue, any guru can give a bit more suggestions ? no one encounter this ?

End of day, I resorted to store the long certificate string directly into separate files instead of saving it as a JSON format into file. but this is not my ideal solution and also make me a bit worry about the entire library .. :(

Justin