修改通过解析字符串文字创建的 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 documentation.
中的示例非常相似
我第一次尝试解决方案是设置 "param1" 的 type 以便 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);
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
会分配新的内存来复制"new value 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
当我第一次遇到这种情况时,我对这种行为感到困惑。该示例与 cJSON documentation.
中的示例非常相似我第一次尝试解决方案是设置 "param1" 的 type 以便 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);
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
会分配新的内存来复制"new value 1"。