C语言调用json_object_put释放JSON根对象hb触发断言失败问题
断言触发根本原因
报错核心是违反json-c库的内存管理规则,复用同一个JSON对象实例添加到父对象的多个键位,导致引用计数错乱,对象被提前释放后重复执行减引用操作。
json-c的内存管理基于引用计数,核心规则如下:
- 所有
json_object_new_*系列接口创建的对象,初始引用计数为1。 - 调用
json_object_object_add()将子对象挂载到父对象时,父对象直接获得子对象的所有权,子对象引用计数不会自动增加。后续父对象被释放时,会对自身持有的每个子对象调用一次json_object_put(),子对象引用计数减1,归0时自动回收内存。 - 同一个
json_object*指针指向的实例,默认只能被挂载到一个父对象的一个键位下。如果要在多个位置存储相同的值,要么为每个位置单独创建新实例,要么手动调用json_object_get()增加引用计数,否则会出现重复释放问题。
对应到你的代码,错误点非常明确:
你只创建了1个值为0的temp_int0对象,却把它同时添加到temp_jobj的status、upgrade、log三个不同键下。当你调用json_object_put(hb)释放根对象时,递归回收流程会对这三个键存储的同一个temp_int0连续执行3次put:
- 第一次
put:temp_int0引用计数从1降到0,对象内存被直接释放 - 后续两次
put:操作已经被回收的野指针,此时对象内存中存储的_ref_count值为0,直接触发jso->_ref_count > 0断言。
你之前手动调用json_object_put()释放所有子对象的写法本身就是错误的,属于双重释放,当时没有触发断言只是未定义行为的巧合,实际已经存在内存破坏问题。
正确释放方法
- 修复对象复用问题:不要共用同一个JSON实例给多个字段赋值。对于值均为0的
status、upgrade、log三个字段,分别创建独立的int对象即可,示例代码如下:
// 移除原来共用的temp_int0,为每个0值字段单独创建实例 json_object *temp_int1 = json_object_new_int(1); json_object *status_val = json_object_new_int(0); json_object *upgrade_val = json_object_new_int(0); json_object *log_val = json_object_new_int(0); json_object *tid = json_object_new_int(1210254506); json_object *fix = json_object_new_int(3); json_object *temp_string = json_object_new_string("obu-hmi-commsignia"); json_object_object_add(temp_jobj, "status", status_val); json_object_object_add(temp_jobj, "tempID", tid); json_object_object_add(temp_jobj, "firmware", temp_string); json_object_object_add(temp_jobj, "sync", temp_int1); json_object_object_add(temp_jobj, "upgrade", upgrade_val); json_object_object_add(temp_jobj, "log", log_val); // 其余字段创建、挂载逻辑保持不变
如果确实需要复用同一个对象实例(不推荐,尤其对int、string这类轻量对象),每多挂载一次就需要手动调用一次json_object_get(对象指针)增加引用计数,保证引用计数和挂载次数匹配。
- 释放逻辑只需要保留根对象的释放即可:所有挂载到父对象上的子对象,不需要手动调用
json_object_put(),只需要在序列化完成后对根对象执行一次json_object_put(hb),库会自动递归回收所有子对象的内存,不会产生泄漏。 - 额外注意:
json_object_to_json_string()返回的字符串由库内部管理,不需要手动free,生命周期和绑定的JSON根对象一致,根对象释放后该指针立即失效,你当前用strcpy拷贝到本地缓冲区的写法是安全的。
修正后循环末尾的释放部分只需要保留以下代码即可,所有对子对象手动put的代码全部删除:
json_object_put(hb); free(rsu_array); free(obu_array);
内容的提问来源于stack exchange,提问作者ofstack773
相关产品推荐
相关产品推荐

