Memory issue with using C++ Protobuf in a DLL

207 views
Skip to first unread message

RZahraie

unread,
Oct 17, 2022, 11:27:59 AM10/17/22
to Protocol Buffers
Greetings

A DLL has been created that will accept any Protobuf message which through the use of reflection, will be filled with data from a database and then returned to the client. The database table name is mapped to the message name and the corresponding table columns are mapped to the message member names.

A typical message will have a .proto file as the following:

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

The code snippets for the DLL functions are as follow:

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 {
           //read values from database for each corresponding field and set value
           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, 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;

              }
}

The client call to the DLL is:

void CallDLL()
{
    OperatingSystemInfo* osi = new OperatingSystemInfo();
   
    ReadMessage(osi);
   
    delete osi;
}

The problem is that when the application is about to terminate, the 'Destroy' method for the last string in the message, 'serialnumber', causes a memory error (__acrt_first_block == header in 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() {

  delete tagged_ptr_.GetIfAllocated(); //<----- Line 233 in arenastring.cc -> leads to assertion Expession: __acrt_first_block == header in debug_heap.ccp
}

Naturally this is an attempt to free an already freed memory.  It is likely that allocating the memory outside of the DLL is a factor but the nature of the project is such that the DLL has no knowledge of Protobuf message types. Hence the reason that reflection is used.

Any helps or hints in resolving this issue is greatly appreciated.


Reply all
Reply to author
Forward
0 new messages