C程序使用Jansson时json_object_set引发二次调用崩溃问题
Jansson库更新JSON时的崩溃问题分析
配置示例JSON
{ "nodes": { "master": "10.0.0.9", "connected": [ { "socket": 18, "IP": "10.0.0.9" } ] } }
相关代码片段
STATUS writeMasterNode(char *newMaster) { static char configFilename[] = "/path/to/file.json"; obj = json_load_file(configFilename, 0, &error); // check to see if the string parsed fine if (!obj) { printf("Error parsing system configuration on line %d, column %d:%s", error.line, error.column, error.text); return; } // read the object into a temporary json objects node_obj = json_object_get(obj, "nodes"); if (!node_obj) { node_obj = json_pack("{{s:s},[{s:i},{s:s}]}", "master", NULL, "socket", NULL, "IP", NULL); } master_obj = json_object_get(node_obj, "master"); connected_obj = json_object_get(node_obj, "connected"); //Update //************* Good code *************** master_obj = json_string(newMaster); json_object_set(node_obj, "master", master_obj); //*************************************** // //************* Bad Code *************** //json_object_set(node_obj, "master", json_string(newMaster)) //************************************** // json_object_set(obj, "nodes", node_obj); //Write if (!obj) { printf("Error parsing system configuration on line %d, column %d:%s", error.line, error.column, error.text); return; } else { json_dump_file(obj, configFilename, JSON_INDENT(2)); } //Cleanup json_decref(obj); json_decref(node_obj); son_decref(connected_obj); // 此处存在笔误,应为json_decref json_decref(master_obj); }
问题
使用json_object_set(node_obj, "master", json_string(newMaster))时,程序首次执行可正常更新文件,但二次调用该函数时会崩溃;改用分步赋值写法后,函数可多次调用无异常,请问异常原因是什么?
原因解析
核心问题源于Jansson的引用计数机制和代码中对master_obj的错误处理:
Jansson引用计数规则:
json_string()创建的新对象初始引用计数为1;json_object_set()会将传入对象的引用计数加1,由目标对象(node_obj)持有该引用。
“Bad Code”的崩溃逻辑:
- 直接调用
json_object_set(node_obj, "master", json_string(newMaster))时,新创建的字符串对象被node_obj引用(计数变为2),但这个对象没有赋值给master_obj,此时master_obj仍然指向旧的master字符串对象(从json_object_get获取的)。 - 后续执行
json_decref(master_obj)时,旧对象的引用计数被减至0并被释放,但node_obj还持有该对象的引用,导致悬空指针。 - 第二次调用函数加载JSON时,
node_obj尝试访问已被释放的旧对象,触发程序崩溃。
- 直接调用
“Good Code”正常的原因:
- 分步赋值时,
master_obj被更新为指向新创建的字符串对象; json_object_set()将新对象的引用计数加1(变为2),后续json_decref(master_obj)将计数减回1,node_obj仍持有合法引用,不会出现悬空指针问题。
- 分步赋值时,
另外注意代码中的笔误:son_decref(connected_obj)应为json_decref(connected_obj),但这不是本次崩溃的直接诱因。
内容的提问来源于stack exchange,提问作者Doug Ferguson
相关产品推荐
相关产品推荐

