简体   繁体   中英

Protobuf Union Message Exception

I have a simple Client/Server that is using Protobuf to send messages back and forth. I am trying to use a Union that has a message with unions of possible message types int it. See the proto file below.

import "Heartbeat.proto";

message PBMessage
{
    optional Heartbeat heartbeat = 1;
    optional HeartbeatAck heartbeatAck = 2;
}

The heartbeat.proto contains the definition of those other messages.

I attempt to add a heartbeat to the message and send that to the server. The server actually receives this message fine but it appears that the client is performing a cleanup when the function returns and then excepts. I believe this has to do with the set_allocated_heartbeat function call. I have attempted to make the heartbeat structure itself a member of the class but that changed nothing.

Here is the client code to send the hearbeat message.

void MyClass::sendHeartBeat(void)
{
    HsmHeartbeat heartbeat;
    unsigned char buffer[1024];

    heartbeat.set_sequenceid(m_currentHBSequence++);

    m_Message.set_allocated_heartbeat(&heartbeat);

    if(heartbeat.IsInitialized() && m_Message.IsInitialized())
    {        
        google::protobuf::io::ArrayOutputStream arr(buffer, sizeof(buffer));
        google::protobuf::io::CodedOutputStream output(&arr);

        m_Message.SerializeToCodedStream(&output);

        sendto(m_ClientSocket, (char*) buffer, output.ByteCount(), 0, (sockaddr *) &m_ClientSendSocket, sizeof(m_ClientSendSocket));
    }
}

Here is the stack trace:

*** glibc detected *** ./client: free(): invalid pointer: 0xbfd882e0 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x73e42)[0xb74d2e42]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb76f851f]
./client[0x804a7a2]
./client[0x804da00]
./client[0x804d7a3]
./client[0x804db01]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb74784d3]
./client[0x804a179]

EDIT: Clarification, m_Message is a PBMessage.

The set_allocated_ methods take ownership of the parameter. You should never pass in a stack-allocated object, only a heap-allocated one. The parent message will take care of deleting that object later on. (Relying on calling release_ later on to prevent deletion is fragile; I'd recommend against it.)

For your node, I'd suggest instead that you simply use mutable_heartbeat() to get an instance of the sub-object. Note that since you're reusing the parent message ( m_Message ), the inner message will be reused too -- when m_Message is cleared, it places all its children in a freelist to be reused later. So, using mutable_heartbeat() will only allocate memory the first time, if that's what you're worried about.

PS. instead of setting up ArrayOutputStream and CodedOutputStream , do this:

int size = m_Message.ByteSize();
assert(size < sizeof(buffer));
m_Message.SerializeWithCachedSizesToArray(buffer);

It'll be faster.

Solution:

Add m_Message.release_heartbeat() prior to exiting the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM