-1

当使用 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
4

2 回答 2

0

当我第一次遇到这种情况时,我对这种行为感到困惑。该示例与 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() 分配的孤立内存 malloc 导致的内存泄漏。

最终代码如下所示:

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);
于 2016-05-01T15:59:58.827 回答
0

cJSON 是一个非常好的库,简单整洁,但需要了解一些事情:

cJSON_GetObjectItem(command,"param1")->valuestring

是一个char *,在这个例子中解析后。

由于您将其替换为"new value 1", const char *,因此在删除 时jsonMsg,删除命令会尝试释放该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"));

或者

如果你坚持手动操作,ok:

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

但是如果您手动操作,则应type cJSON_IsReference在尝试释放之前检查,其次strdup将分配新内存以复制“新值 1”。

于 2017-04-11T05:41:26.423 回答