cJSON
cJSON copied to clipboard
cJSON_Print memory leak in ESP-IDF
Hello,
With further checking, cJSON_Print
will cause an internal heap leak, which is unknown. The current testing environment is under ESP-IDF v4.4.
The create_monitor
example is used.
ESP32 code:
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "cJSON.h"
//create a monitor with a list of supported resolutions
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor(void)
{
/* Checking heap */
printf("\nENTERS CREATE_MONITOR: free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
const unsigned int resolution_numbers[3][2] = {
{1280, 720},
{1920, 1080},
{3840, 2160}
};
char *string = NULL;
cJSON *name = NULL;
cJSON *resolutions = NULL;
cJSON *resolution = NULL;
cJSON *width = NULL;
cJSON *height = NULL;
size_t index = 0;
/* Checking heap */
printf("\nBEFORE cJSON_CREATEOBJECT: free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
cJSON *monitor = cJSON_CreateObject();
if (monitor == NULL)
{
goto end;
}
name = cJSON_CreateString("Awesome 4K");
if (name == NULL)
{
goto end;
}
/* after creation was successful, immediately add it to the monitor,
* thereby transferring ownership of the pointer to it */
cJSON_AddItemToObject(monitor, "name", name);
resolutions = cJSON_CreateArray();
if (resolutions == NULL)
{
goto end;
}
cJSON_AddItemToObject(monitor, "resolutions", resolutions);
for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
{
resolution = cJSON_CreateObject();
if (resolution == NULL)
{
goto end;
}
cJSON_AddItemToArray(resolutions, resolution);
width = cJSON_CreateNumber(resolution_numbers[index][0]);
if (width == NULL)
{
goto end;
}
cJSON_AddItemToObject(resolution, "width", width);
height = cJSON_CreateNumber(resolution_numbers[index][1]);
if (height == NULL)
{
goto end;
}
cJSON_AddItemToObject(resolution, "height", height);
}
/* Checking heap */
printf("\nBEFORE cJSON PRINT: free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
string = cJSON_Print(monitor);
/* Checking heap */
printf("\nAFTER cJSON PRINT: free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
if (string == NULL)
{
fprintf(stderr, "Failed to print monitor.\n");
}
end:
/* Checking heap */
printf("\nBEFORE cJSON DELETE: free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
cJSON_Delete(monitor);
/* Checking heap */
printf("\nAFTER cJSON DELETE: free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
return string;
}
void app_main(void)
{
printf("Hello world!\n");
/* Print chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
printf("silicon revision %d, ", chip_info.revision);
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
/* HEAP Managment Checking */
/* Checking heap */
printf("\n free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
char *monitor = create_monitor();
printf("Monitor: %s\n", monitor);
/* Checking heap */
printf("\n free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
free(monitor);
/* Checking heap */
printf("\n free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
vTaskDelay(1000 / portTICK_PERIOD_MS);
/* Checking heap */
printf("\n free heap size = %d \t min_free_heap_size = %d \n",esp_get_free_heap_size(),esp_get_minimum_free_heap_size());
}
Many heap checks are made during the program for easier debugging.
Output:
Hello world!
This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, silicon revision 3, 2MB external flash
Minimum free heap size: 295096 bytes
free heap size = 295096 min_free_heap_size = 295096
ENTERS CREATE_MONITOR: free heap size = 295096 min_free_heap_size = 295096
BEFORE cJSON_CREATEOBJECT: free heap size = 295096 min_free_heap_size = 295096
BEFORE cJSON PRINT: free heap size = 294424 min_free_heap_size = 294424
AFTER cJSON PRINT: free heap size = 294032 min_free_heap_size = 293948
BEFORE cJSON DELETE: free heap size = 294032 min_free_heap_size = 293948
AFTER cJSON DELETE: free heap size = 294704 min_free_heap_size = 293948
Monitor: {
"name": "Awesome 4K",
"resolutions": [{
"width": 1280,
"height": 720
}, {
"width": 1920,
"height": 1080
}, {
"width": 3840,
"height": 2160
}]
}
free heap size = 294704 min_free_heap_size = 293948
free heap size = 294880 min_free_heap_size = 293948
free heap size = 294880 min_free_heap_size = 293948
With the calculation of how much heap is used: 294424-294032=392. And when free(monitor)
is called: 294880-294704=176, where 392-176=216 is leaked.
The system started with 295096, where if the 216 was added back into 294880 then there will be no leaks.
Is there any reason why cJSON_Print
will cause internal leaks even after freeing the char *
?
Thank you
You should close this issue, since the problem is not with cJSON, and track it in the IDF issue. In the future, avoid escalating things without any need whatsoever.