You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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”的崩溃逻辑:

    1. 直接调用json_object_set(node_obj, "master", json_string(newMaster))时,新创建的字符串对象被node_obj引用(计数变为2),但这个对象没有赋值给master_obj,此时master_obj仍然指向旧的master字符串对象(从json_object_get获取的)。
    2. 后续执行json_decref(master_obj)时,旧对象的引用计数被减至0并被释放,但node_obj还持有该对象的引用,导致悬空指针。
    3. 第二次调用函数加载JSON时,node_obj尝试访问已被释放的旧对象,触发程序崩溃。
  • “Good Code”正常的原因:

    1. 分步赋值时,master_obj被更新为指向新创建的字符串对象;
    2. json_object_set()将新对象的引用计数加1(变为2),后续json_decref(master_obj)将计数减回1,node_obj仍持有合法引用,不会出现悬空指针问题。

另外注意代码中的笔误:son_decref(connected_obj)应为json_decref(connected_obj),但这不是本次崩溃的直接诱因。

内容的提问来源于stack exchange,提问作者Doug Ferguson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:45:17