IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    c++ protobuf中set_allocated引起的double free core dump

    五四陈科学院发表于 2016-03-24 16:09:04
    love 0

    以下内容由[五四陈科学院]提供

    c

    在c++中使用protobuf的时候,大多数元素,我们可以直接set_xxx,如果有嵌套进去一个对象,会有set_allocated_xxx的方法和mutable_xxx的方法。

    这里有一个坑。

    现象

    首先,看pb定义:

    package test;
      message a{
          required uint32 aa = 1;
      }
      
      message b{
          required a aaa = 1;
      }

    如果使用set_allocated_aaa,同时传入了一个定义好的a,而不是new的a,如下:

    void bad_case(){
          a aa;
          b bb;
          aa.set_aa(1);
          bb.set_allocated_aaa(&aa);
      }

    编译的时候不会有错误,一运行就出问题了:

    *** glibc detected *** ./test.run: double free or corruption (out): 0x00007fffc65ade20 ***

    正确的写法

    下面的写法,不会有问题:

    int good_case1(){
          a* aa = new a();
          b bb;
          aa->set_aa(1);
          bb.set_allocated_aaa(aa);
          return 0;
      }

    下面的写法,也不会有问题:

    void good_case2(){
          a aa;
          b bb;
          aa.set_aa(1);
          bb.mutable_aaa()->MergeFrom(aa);
      }

    原因

    在pb生成的对象中,析构函数统一都要进行对象的delete作:

    b::~b() {
        // @@protoc_insertion_point(destructor:test.b)
        SharedDtor();
      }
      
      void b::SharedDtor() {
        if (this != default_instance_) {
          delete aaa_;
        }
      }

    通过定义得到的一个变量,只在栈上临时生成,在函数生命周期后自动清理,而将地址给了一个pb后,执行结束时会进行手动delete,从而导致了double free。

    通过new得到的一个对象,放在堆上,手动delete才会清理。

    good_case2正确的原因,是因为mutable_aaa的代码里new了一个a。

    inline ::test::a* b::mutable_aaa() {
        set_has_aaa();
        if (aaa_ == NULL) aaa_ = new ::test::a;
        // @@protoc_insertion_point(field_mutable:test.b.aaa)
        return aaa_;
      }

    结论

    使用pb的set_allocated_xxx要小心,没有显式allocate的东西不要往里传。

    文中涉及的代码地址:https://github.com/54chen/test


    想快点找到作者也可以到weibo上留言: @54chen
    或者你懒得带上,请到新浪微博:@54chen


沪ICP备19023445号-2号
友情链接