简体   繁体   中英

cJSON Memory leak when freeing cJSON object

I am facing an issue while using the cJSON Library. I am assuming that there is a memory leak that is breaking the code after a certain time (40 mins to 1 hr).

I have copied my code below:

void my_work_handler_5(struct k_work *work)
{

     char *ptr1[6];
     int y=0;
     static int counterdo = 0;
     char *desc6 = "RSRP";
     char *id6 = "dBm";
     char *type6 = "RSRP";
     char rsrp_str[100];
     snprintf(rsrp_str, sizeof(rsrp_str), "%d", rsrp_current);

     sensor5 = cJSON_CreateObject();

    cJSON_AddItemToObject(sensor5, "description", cJSON_CreateString(desc6));
    cJSON_AddItemToObject(sensor5, "Time", cJSON_CreateString(time_string));
    cJSON_AddItemToObject(sensor5, "value", cJSON_CreateNumber(rsrp_current));
    cJSON_AddItemToObject(sensor5, "unit", cJSON_CreateString(id6));
    cJSON_AddItemToObject(sensor5, "type", cJSON_CreateString(type6));

       /* print everything */
        ptr1[counterdo] = cJSON_Print(sensor5);

        printk("Counterdo value is : %d\n", counterdo);
         
        cJSON_Delete(sensor5);
        
         counterdo = counterdo + 1;
        
        if (counterdo==6){
        for(y=0;y<=counterdo;y++){
         free(ptr1[y]);
         }
         counterdo = 0;
         }

        return;
}

I read some other threads regarding freeing up the memory and tried to do the same. Can anyone let me know if this is the right approach to free up the space allocated to the cJSON Object.

Regards, Adeel.

Since cJSON is a portable library with no dependencies, this is better to look for a potential issue in your code on a PC: they are specialized tools available in this environment for facilitating the investigation. I am assuming here you have a Linux system, a Windows system with WSL or WSL2 installed, or a Linux virtual machine, available, and gcc, valgrind installed.

A minimal, self-contained, portable version of your code could be:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <cJSON.h>

static int rsrp_current = 1;
static char *time_string = NULL;

void
my_work_handler_5 ()
{
  char *ptr1[6];
  int y = 0;
  static int counterdo = 0;
  char *desc6 = "RSRP";
  char *id6 = "dBm";
  char *type6 = "RSRP";
  char rsrp_str[100];
  snprintf (rsrp_str, sizeof (rsrp_str), "%d", rsrp_current);

  cJSON *sensor5 = cJSON_CreateObject ();

  cJSON_AddItemToObject (sensor5, "description", cJSON_CreateString (desc6));
  cJSON_AddItemToObject (sensor5, "Time", cJSON_CreateString (time_string));
  cJSON_AddItemToObject (sensor5, "value", cJSON_CreateNumber (rsrp_current));
  cJSON_AddItemToObject (sensor5, "unit", cJSON_CreateString (id6));
  cJSON_AddItemToObject (sensor5, "type", cJSON_CreateString (type6));

  /* print everything */
  ptr1[counterdo] = cJSON_Print (sensor5);

  printf ("Counterdo value is : %d\n", counterdo);

  cJSON_Delete (sensor5);

  counterdo = counterdo + 1;

  if (counterdo == 6)
    {
      for (y = 0; y <= counterdo; y++)
    {
      free (ptr1[y]);
    }
      counterdo = 0;
    }

  return;
}

int
main (int argc, char **argv)
{
  time_t curtime;

  time (&curtime);

  for (int n = 0; n < 3 * 6; n++)
    {
      my_work_handler_5 ();
    }
}

Build procedure:

wget https://github.com/DaveGamble/cJSON/archive/v1.7.14.tar.gz
tar zxf v1.7.14.tar.gz
gcc -g -O0 -IcJSON-1.7.14 -o cjson cjson.c cJSON-1.7.14/cJSON.c

Running valgrind on the program:

valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose   ./cjson

..indicates some memory is being freed that was not previously allocated: Invalid free() / delete / delete[] / realloc() :

==6747== 
==6747== HEAP SUMMARY:
==6747==     in use at exit: 0 bytes in 0 blocks
==6747==   total heap usage: 271 allocs, 274 frees, 14,614 bytes allocated
==6747== 
==6747== All heap blocks were freed -- no leaks are possible
==6747== 
==6747== ERROR SUMMARY: 21 errors from 2 contexts (suppressed: 0 from 0)
==6747== 
==6747== 3 errors in context 1 of 2:
==6747== Invalid free() / delete / delete[] / realloc()
==6747==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==6747==    by 0x1094DA: my_work_handler_5 (cjson.c:42)
==6747==    by 0x10955A: main (cjson.c:59)
==6747==  Address 0x31 is not stack'd, malloc'd or (recently) free'd
==6747== 
==6747== 
==6747== 18 errors in context 2 of 2:
==6747== Conditional jump or move depends on uninitialised value(s)
==6747==    at 0x483C9F5: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==6747==    by 0x1094DA: my_work_handler_5 (cjson.c:42)
==6747==    by 0x10955A: main (cjson.c:59)
==6747==  Uninitialised value was created by a stack allocation
==6747==    at 0x109312: my_work_handler_5 (cjson.c:11)
==6747== 
==6747== ERROR SUMMARY: 21 errors from 2 contexts (suppressed: 0 from 0)

Replacing:

  for (y = 0; y <= counterdo; y++)
{
  free (ptr1[y]);
}

by:

  for (y = 0; y < counterdo; y++)
{
  free (ptr1[y]);
}

and executing valgrind again:

==6834== 
==6834== HEAP SUMMARY:
==6834==     in use at exit: 1,095 bytes in 15 blocks
==6834==   total heap usage: 271 allocs, 256 frees, 14,614 bytes allocated
==6834== 
==6834== Searching for pointers to 15 not-freed blocks
==6834== Checked 75,000 bytes
==6834== 
==6834== 1,095 bytes in 15 blocks are definitely lost in loss record 1 of 1
==6834==    at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==6834==    by 0x10B161: print (cJSON.c:1209)
==6834==    by 0x10B25F: cJSON_Print (cJSON.c:1248)
==6834==    by 0x1094AB: my_work_handler_5 (cjson.c:30)
==6834==    by 0x10959C: main (cjson.c:59)
==6834== 
==6834== LEAK SUMMARY:
==6834==    definitely lost: 1,095 bytes in 15 blocks
==6834==    indirectly lost: 0 bytes in 0 blocks
==6834==      possibly lost: 0 bytes in 0 blocks
==6834==    still reachable: 0 bytes in 0 blocks
==6834==         suppressed: 0 bytes in 0 blocks
==6834== 
==6834== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Some memory is definitively being leaked.

The reason is that char *ptr1[6] is not static, and is therefore created on the stack every time my_work_handler_5() is being called. The pointers that were returned are by cJSON_Print() are therefore lost between two calls, and free() is being called on arbitrary pointer values, since ptr1[] is not initialized as it could be:

char *ptr1[6] = { NULL, NULL, NULL, NULL, NULL, NULL };

Since you are freeing memory every 6 calls, this is causing the memory leak you were suspecting.

Replacing:

char *ptr1[6];

by:

static char *ptr1[6];

compiling, running valgrind again:

==6927== 
==6927== HEAP SUMMARY:
==6927==     in use at exit: 0 bytes in 0 blocks
==6927==   total heap usage: 271 allocs, 271 frees, 14,614 bytes allocated
==6927== 
==6927== All heap blocks were freed -- no leaks are possible
==6927== 
==6927== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

The modified version of the program should now work on your bare-metal system.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM