protobuf coredump在函数

时间:2016-05-27 04:25:06

标签: c++ protocol-buffers

我遇到了一个关于使用protobuf动态创建消息的奇怪问题。如下面的代码所示,它可以正常工作。但如果我以下列方式注释掉主要功能:

#if 0
    const Descriptor* desc = pb.pool()->FindMessageTypeByName("SvrRegRsp");
    DynamicMessageFactory factory;
    const Message *message = factory.GetPrototype(desc);
    Message *p_msg = message->New();
#endif
    Message* p_msg = get_msg(&pb);

它核心!似乎主要的不同只是在函数中包装消息的创建。当我查询调用堆栈时:

   (gdb) where
   #0  0x0000000001436ed0 in ?? ()
   #1  0x00007ff218c8f0e3 in google::protobuf::internal::ReflectionOps::Clear (message=0x1437aa0)
at google/protobuf/reflection_ops.cc:133
   #2  0x00007ff218c3328b in InlineParseFromCodedStream (message=0x1437aa0, input=0x7ffc82fc3aa0)
at google/protobuf/message_lite.cc:131
   #3  InlineParseFromArray (message=0x1437aa0, size=<optimized out>, data=<optimized out>)
at google/protobuf/message_lite.cc:143
   #4  google::protobuf::MessageLite::ParseFromArray (this=0x1437aa0, data=<optimized out>, 
size=<optimized out>) at google/protobuf/message_lite.cc:207
   #5  0x000000000040137e in parse_msg (p_msg=0x1437aa0, 
buf=0x7ffc82fc3dc0 "\b\237\215\006\022\024QT-SIM-504761089-101", len=26) at pb_test.cpp:46
   #6  0x000000000040172d in main (argc=1, argv=0x7ffc82fc42c8) at pb_test.cpp:95
   (gdb) fr 1
   #1  0x00007ff218c8f0e3 in google::protobuf::internal::ReflectionOps::Clear (message=0x1437aa0)
at google/protobuf/reflection_ops.cc:133
   133    reflection->ListFields(*message, &fields);
   (gdb) p reflection->ListFields
   Cannot take address of method ListFields.

似乎ListFields是Null(纯虚函数调用)。任何人都可以帮助我找出为什么会发生这种情况?为什么在将创建包装在函数中时代码不起作用。提前致谢!

在文件test.proto中:

message SvrRegRsp{    
  required int32 RetCode = 1;
  required string SID = 2;
}

cpp文件:

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

#include <unistd.h>

#include <string>

#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/compiler/importer.h>

using namespace google::protobuf;
using namespace google::protobuf::compiler;

enum {
    MAX_PACKET_LEN = 1024, 
};

int gen_msg(Importer* pb, char* buf, int* len)
{
    const Descriptor* desc = pb->pool()->FindMessageTypeByName("SvrRegRsp");
    DynamicMessageFactory factory;
    const Message *message = factory.GetPrototype(desc);
    Message *p_msg = message->New();
    const Reflection *reflection = p_msg->GetReflection();

    const FieldDescriptor *field =  desc->field(1);
    reflection->SetString(p_msg, field, "QT-SIM-504761089-101");

    field =  desc->field(0);
    reflection->SetInt32(p_msg, field, 99999);

    p_msg->SerializeToArray(buf, *len) ;
    *len = p_msg->ByteSize();

    std::string s = p_msg->DebugString();
    printf("req: %s\nsize: %d\n", s.c_str(), *len);

    return 0;
}

int parse_msg(Message* p_msg, const char* buf,  int len)
{
    if(p_msg) {
        p_msg->ParseFromArray(buf, len); // core here, because p_msg vptr is NULL.

        std::string s = p_msg->DebugString();
        printf("rsp2:\n%s\nsize: %d\n", s.c_str(), len);
    }

    return 0;
}

Message* get_msg(Importer* pb)
{
    const Descriptor* desc = pb->pool()->FindMessageTypeByName("SvrRegRsp");

    DynamicMessageFactory factory;
    const Message *message = factory.GetPrototype(desc);
    Message *p_msg = message->New();
    return p_msg;
}


int main(int argc, char** argv)
{
    char cwd[256] = {0};
    getcwd(cwd, sizeof(cwd));

    printf("cwd: %s\n", cwd);

    DiskSourceTree disk;
    disk.MapPath("", cwd);
    Importer pb(&disk, NULL);

     const FileDescriptor* file_desc = pb.Import("test.proto");
    if(!file_desc) {
        return -1;
    }

    char packet[MAX_PACKET_LEN] = {0};
    int len = MAX_PACKET_LEN;

    gen_msg(&pb, packet, &len);

//#if 0
    const Descriptor* desc = pb.pool()->FindMessageTypeByName("SvrRegRsp");
    DynamicMessageFactory factory;
    const Message *message = factory.GetPrototype(desc);
    Message *p_msg = message->New();
//#endif
//    Message* p_msg = get_msg(&pb);

    parse_msg(p_msg, packet, len);

    return 0;
}

1 个答案:

答案 0 :(得分:0)

检查生成的factory.GetPrototype(desc);message->New();代码 如果他们保留指针并且在返回呼叫者时不释放,则 然后当工厂超出范围时,它们就会被破坏而你正在访问悬空指针。