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

C++ Protobuf在DLL中使用时的内存释放异常问题求助

Protobuf反射填充字符串字段后内存释放错误问题

问题背景

我们开发了一个DLL,可接收任意Protobuf消息,通过反射从数据库填充数据后返回客户端——数据库表名与消息名映射,表字段与消息成员名映射。调用DLL获取填充后的Protobuf消息后,程序退出时触发内存错误,问题出在Reflection类的SetString方法上。该问题曾发布在Google Group的Protobuf群组,但未得到解答。

典型.proto文件示例

message OperatingSystemInfo {
   string manufacturer;
   string name;
   string release;
   string osversion;
   string localename;
   string bootdevice;
   string serialnumber;
}

DLL函数代码片段

void EXPORT_DLL ReadMessage(void* protoBufMessage) {

      Message* msg = static_cast<Message*>(protoBufMessage);
    
      const Descriptor* descriptor = msg->GetDescriptor();
      const Reflection* reflection = msg->GetReflection();
    
      for (int i = 0; i < descriptor->field_count(); i++) {
    
        const FieldDescriptor* field = descriptor->field(i);
        const FieldDescriptor::Type type = field->type();
        bool isRepeated = field->is_repeated();
    
        std::string name = field->name();
    
        if (type == FieldDescriptor::TYPE_MESSAGE) {
            // 暂未处理嵌套消息
        }
        else {
           // 从数据库读取对应字段的值
           string fieldValue;
    
           SetFieldValues(reflection, field, msg, fieldValue);
        }
    }

}
void SetFieldValues(const google::protobuf::Reflection* reflection,
const google::protobuf::FieldDescriptor* field,
google::protobuf::Message* msg,
std::string fieldValue) {

    switch (field->type()) {
        case FieldDescriptor::TYPE_STRING:
            reflection->SetString(msg, field, std::move(fieldValue));
            break;
    
        case FieldDescriptor::TYPE_UINT32:
            break;
    
        case FieldDescriptor::TYPE_UINT64:
            break;
     
        case FieldDescriptor::TYPE_BOOL:
            break;
    
        case FieldDescriptor::TYPE_ENUM:
            break;
    
        default:
            break;
    }

}

客户端调用代码

void CallDLL()
{
    OperatingSystemInfo* osi = new OperatingSystemInfo();

    ReadMessage(osi);
    
    delete osi;
}

错误详情

程序即将终止时,消息中最后一个字符串字段serialnumber的Destroy方法触发内存错误,触发断言__acrt_first_block == header(来自debug_heap.ccp):

inline void OperatingSystemState::SharedDtor() {
    GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
    _impl_.manufacturer_.Destroy();
    _impl_.name_.Destroy();
    _impl_.release_.Destroy();
    _impl_.osversion_.Destroy();
    _impl_.localename_.Destroy();
    _impl_.bootdevice_.Destroy();
    _impl_.serialnumber_.Destroy(); 
}
void ArenaStringPtr::Destroy() {
        // arenastring.cc第233行触发断言
        delete tagged_ptr_.GetIfAllocated();
}

这显然是重复释放内存的问题,推测内存分配在DLL外部是诱因,但项目特性要求DLL不能知晓Protobuf消息类型,因此必须使用反射,恳请提供解决思路或提示。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 10:45:36