When using cJSON to parse a string literal I was getting a segmentation fault when free'ing the cJSON structure.
The original code was as follows:
char* jsonStr = "{ \"command\" : { \"param1\": \"value1\", \"param2\": \"value2\" } }";
cJSON *jsonMsg = cJSON_Parse(jsonStr);
cJSON *command = CJSON_GetObjectItem(jsonMsg, "command");
cJSON_GetObjectItem(command,"param1")->valuestring = "new value 1";
cJSON_Delete(jsonMsg); // <— segmentation fault
When I first encountered this I was puzzled by the behavior. The example is very similar to the one in the cJSON documentation .
My first attempt at a solution was to set the type of "param1" so that the cJSON_Delete() function wouldn't try to free the memory. That is, set the "cJSON_IsReference" flag in the cJSON->type member.
The updated code was:
char* jsonStr = "{ \"command\" : { \"param1\": \"value1\", \"param2\": \"value2\" } }";
cJSON *jsonMsg = cJSON_Parse(jsonStr);
cJSON *command = CJSON_GetObjectItem(jsonMsg, "command");
cJSON_GetObjectItem(command,"param1")->valuestring = "new value 1";
cJSON_GetObjectItem(command,"param1")->type |= cJSON_IsReference;
cJSON_Delete(jsonMsg);
The final solution was to transfer the contents of the original message into a new cJSON object. This prevented a memory leak due to orphaned memory malloc'd by cJSON_Parse().
The final code looked like this:
char* jsonStr = "{ \"command\" : { \"param1\": \"value1\", \"param2\": \"value2\" } }";
cJSON *jsonMsg = cJSON_Parse(jsonStr);
cJSON *command = CJSON_GetObjectItem(jsonMsg, "command");
cJSON *jsonRes, *command;
jsonRes = cJSON_CreateObject();
command = cJSON_CreateObject()
cJSON_AddItemToObject(jsonRes, "command", command);
cJSON_AddStringToObject(command, cJSON_GetObjectItem(command,"param1")->string, "new value 1");
cJSON_AddItemToObject(jsonRes, "command", command = cJSON_CreateObject());
cJSON_AddStringToObject(command,
cJSON_GetObjectItem(command,"param2")->string,
cJSON_GetObjectItem(command,"param2")->valuestring);
cJSON_Print(jsonRes);
cJSON_Delete(jsonMsg);
cJSON_Delete(jsonRes);
cJSON is a very nice lib, simple and neat, but one need to understand some things:
cJSON_GetObjectItem(command,"param1")->valuestring
is a char *
, after parsing in this example.
Since you replace it with "new value 1"
, being a const char *
, so when deleting the jsonMsg
, the delete command tries to free that const char *
, resulting in a segmentation fault.
there are a couple of approaches:
char* jsonStr = "{ \"command\" : { \"param1\": \"value1\", \"param2\": \"value2\" } }";
cJSON *jsonMsg = cJSON_Parse(jsonStr);
cJSON *command = CJSON_GetObjectItem(jsonMsg, "command");
till here alright,
then one simple command:
cJSON_ReplaceItemInObject(command,"param1", cJSON_CreateString("new value 1"));
and Finish :
cJSON_Print(jsonMsg);
cJSON_Delete(jsonMsg);
Or
cJSON_DeleteItemFromObject(command,"param1");
cJSON_AddItemToObject(command,"param1",cJSON_CreateString("new value 1"));
Or
If you insist on manually manipulating, ok:
free(cJSON_GetObjectItem(command,"param1")->value string);
cJSON_GetObjectItem(command,"param1")->valuestring=strdup("new value 1");
but if you manipulate manually, one should check the type cJSON_IsReference
before trying to free, secondly the strdup
will allocate new memory to copy the "new value 1" in.
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.