簡體   English   中英

修改通過解析字符串文字創建的cJSON結構時的分段錯誤

[英]Segmentation Fault when Modifying a cJSON Struct Created by Parsing a String Literal

當使用cJSON解析字符串文字時,在釋放cJSON結構時遇到分段錯誤。

原始代碼如下:

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

當我第一次遇到這個問題時,我對這種行為感到困惑。 該示例與cJSON 文檔中的示例非常相似。

我第一次嘗試解決方案是設置“ param1”的類型 ,以便cJSON_Delete()函數不會嘗試釋放內存。 也就是說,在cJSON-> type成員中設置“ cJSON_IsReference”標志。

更新的代碼是:

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);

最終的解決方案是將原始消息的內容傳輸到新的cJSON對象中。 這樣可以防止由於cJSON_Parse()分配的孤立內存而導致的內存泄漏。

最終代碼如下所示:

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是一個非常不錯的庫,簡單而整潔,但是需要了解一些事情:

cJSON_GetObjectItem(command,"param1")->valuestring

在此示例中進行分析后為char *

由於您將其替換為"new value 1" (即const char * ,因此在刪除jsonMsg ,delete命令將嘗試釋放該const char * ,從而導致分段錯誤。

有兩種方法:

char* jsonStr = "{ \"command\" : { \"param1\": \"value1\", \"param2\": \"value2\" } }";
cJSON *jsonMsg = cJSON_Parse(jsonStr);
cJSON *command = CJSON_GetObjectItem(jsonMsg, "command");

直到這里,

然后是一個簡單的命令:

cJSON_ReplaceItemInObject(command,"param1", cJSON_CreateString("new value 1"));

和完成:

cJSON_Print(jsonMsg);
cJSON_Delete(jsonMsg);

要么

cJSON_DeleteItemFromObject(command,"param1");
cJSON_AddItemToObject(command,"param1",cJSON_CreateString("new value 1"));

要么

如果您堅持手動操作,那么可以:

free(cJSON_GetObjectItem(command,"param1")->value string);
cJSON_GetObjectItem(command,"param1")->valuestring=strdup("new value 1");

但是如果您手動操作,則應在嘗試type cJSON_IsReference之前檢查type cJSON_IsReference ,其次strdup將分配新內存以復制“新值1”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM