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

C语言mongoc BSON解析场景下结构体指针数组成员赋值问题求解

问题排查

  • 野指针访问:代码中声明的skill_data *parameterset未分配内存空间,就直接访问其成员写入数据,属于典型的未定义行为,是程序故障的核心原因。
  • 类型判断逻辑错误:if (bson_iter_type (&child3) == 0x01 || 0x10 || 0x12)写法不符合C语言语法规则,该表达式会永久返回真(因为0x10为非零常量,逻辑或运算只要有一个操作数非零即返回真),所有类型的字段都会进入数值赋值分支,字符串类型分支永远不会触发。
  • 缺少接口返回值校验:所有bson_iter_find、bson_iter_recurse的返回值都未做完整性校验,只要某一步查找失败,后续使用的迭代器就是非法状态,直接访问会触发内存错误。
  • 数组越界风险:结构体中key、literal、numeral的数组长度均为50,代码未对循环变量i做上限判断,当ParameterSet下的字段数超过50时会发生数组越界,破坏内存结构。
  • 字符串溢出风险:直接使用strcpy拷贝字符串,未判断源字符串长度是否超过目标数组(单个数组容量为50字节)的容量,长字符串会溢出导致内存污染。
  • 错误场景无兜底处理:如果任意一步解析失败,返回的指针未做初始化处理,调用方无法判断解析是否成功。

修复后的参考代码

#include <stdlib.h>
#include <string.h>
#include <bson.h>

typedef struct {
    char key [50][50];
    char literal [50][50];
    double numeral [50];
} skill_data;

skill_data *
mongoc_fetchSkillParameter (const bson_t *recipe, char *skill_id)
{
    bson_iter_t iter;
    bson_iter_t child1;
    bson_iter_t child2;
    bson_iter_t child3;
   
    int i = 0;
    // 给结构体分配内存
    skill_data *parameterset = malloc(sizeof(skill_data));
    if (!parameterset) {
        return NULL;
    }
    // 初始化结构体内容为0
    memset(parameterset, 0, sizeof(skill_data));
    
    bson_iter_init(&iter, recipe);
   
    if (!bson_iter_find (&iter, "Skills") || !BSON_ITER_HOLDS_ARRAY (&iter) || !bson_iter_recurse (&iter, &child1)) {
        free(parameterset);
        return NULL;
    }
    // 注意:此处只取了Skills数组的第一个元素,如果你需要匹配skill_id需要补充遍历查找逻辑
    if (!bson_iter_next (&child1) || !BSON_ITER_HOLDS_DOCUMENT (&child1) || !bson_iter_recurse (&child1, &child2)) {
        free(parameterset);
        return NULL;
    }

    if (!bson_iter_find(&child2, "ParameterSet") || !BSON_ITER_HOLDS_DOCUMENT (&child2) || !bson_iter_recurse (&child2, &child3)) {
        free(parameterset);
        return NULL;
    }

    i = 0;
    while (i < 50 && bson_iter_next (&child3)) {
        // 安全拷贝key,避免溢出
        strncpy(parameterset->key[i], bson_iter_key (&child3), 49);
        parameterset->key[i][49] = '\0';

        bson_type_t type = bson_iter_type(&child3);
        if (type == BSON_TYPE_DOUBLE || type == BSON_TYPE_INT32 || type == BSON_TYPE_INT64) {
            parameterset->numeral[i] = bson_iter_as_double (&child3);
            // 非字符串类型的literal默认留空即可,因为结构体已经memset为0
        } else if (type == BSON_TYPE_UTF8) {
            const char *str_val = bson_iter_utf8 (&child3, NULL);
            strncpy(parameterset->literal[i], str_val, 49);
            parameterset->literal[i][49] = '\0';
        }
        i++;    
    }
 
    return parameterset;
}

额外说明

  1. 代码中传入的skill_id参数暂未使用,原逻辑只取了Skills数组的第一个元素,如果你需要根据skill_id匹配对应的技能项,需要补充遍历Skills数组的逻辑。
  2. 调用方使用完返回的skill_data指针后,需要主动调用free释放内存,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 13:24:00