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
相关产品推荐
相关产品推荐

