【问题标题】:boost::spirit::hold_any memory corruptionboost::spirit::hold_any 内存损坏
【发布时间】:2014-06-05 16:44:40
【问题描述】:

我的代码库很大,可以使用boost::anyboost::spirit::hold_any(取决于宏定义)。

hold_any 似乎与boost::any 兼容(例如How to print boost::any to a stream?Type erasure - Part IV)并且速度更快(Why you shouldn’t use boost::any),但我在使用hold_any(Boost v1.55 / 1.54 / 1.53)。

这是一个最小的工作示例,显示与原始代码相同的问题:

#include <iostream>
#include <string>
#include <vector>

#include <boost/spirit/home/support/detail/hold_any.hpp>

typedef boost::spirit::hold_any any;
typedef std::vector<any> vany;

int main()
{
  vany data0, data1;

  for (unsigned i(0); i < 1000; ++i)
  {
    std::string s("test_test_test");
    data0.push_back(any(s));
  }

  const unsigned n(data0.size());
  vany::iterator iter(data0.begin());

  for (unsigned i(0); i < n; ++i)
  {
    std::cout << "Moving " << i << std::endl;

    data1.push_back(*iter);
    iter = data0.erase(iter);
  }

  return 0;
}

程序似乎运行正常:

  • boost::spirit::hold_any 更改为boost::any
  • hold_any 的内容更改为足够小的数据类型以执行小缓冲区优化(例如,从std::stringint)。

在 Boost Spirit 等广泛使用的库中可能存在一些重大错误似乎很奇怪,但是

  • 我很难找到示例中的错误;
  • 我试过 g++/clang++ 没有成功。

这个例子有什么问题?

【问题讨论】:

    标签: c++ boost boost-spirit memory-corruption boost-any


    【解决方案1】:

    您应该使用 hold_any,因为它在 detail/hold_any.hpp 中是有原因的。

    也就是说,hold_any 的复制分配似乎已损坏。我创建了 a pull request on github 并提出了修复建议。

    如果没有修复,下面的程序演示了 UB(因为编译器生成了一个首选的浅赋值运算符):

    #include <iostream>
    #include <string>
    
    #include <boost/spirit/home/support/detail/hold_any.hpp>
    
    typedef boost::spirit::hold_any any;
    
    int main()
    {
        any b;
        {
            any a;
            a = std::string("test_test_test");
            b = a;
        }
    
        std::cout << "b: " << b << '\n';
    }
    

    在 valgrind 下运行时:

    ==11827== Invalid read of size 8
    ==11827==    at 0x5E9D793: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std
    ==11827==    by 0x4012FC: boost::spirit::detail::fxns<mpl_::bool_<true> >::type<std::string, char>::stream_out(std::ostream&, void* const*) (hold_any.hpp:113)
    ==11827==    by 0x4010F5: std::basic_ostream<char, std::char_traits<char> >& boost::spirit::operator<< <char>(std::basic_ostream<char, std::char_traits<char> >&, boost::spirit::basic_hold_any<char> const&) (hold_any.hpp:368)
    ==11827==    by 0x400FC9: main (test.cpp:17)
    ==11827==  Address 0x8ac1650 is 0 bytes inside a block of size 39 free'd
    ==11827==    at 0x4C2BADC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==11827==    by 0x5EC405E: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
    ==11827==    by 0x401204: boost::spirit::detail::fxns<mpl_::bool_<true> >::type<std::string, char>::static_delete(void**) (hold_any.hpp:89)
    ==11827==    by 0x401328: boost::spirit::basic_hold_any<char>::~basic_hold_any() (hold_any.hpp:246)
    ==11827==    by 0x4010B4: boost::spirit::basic_hold_any<char>::~basic_hold_any() (hold_any.hpp:245)
    ==11827==    by 0x400FA0: main (test.cpp:15)
    

    【讨论】:

    • 谢谢,我不知道。很遗憾hold_any 不是现成的boost:any 替代品:SBO 在我的程序中是一个很大的收获。你知道其他的区别吗?如果这是“唯一”一个,那么也许可以解决它。
    • 更新 pull request 以获得正确的 c++11 支持
    • 同时我找到了这张旧票:basic_hold_any missing assignment operator。在我看来,非模板赋值构造函数也应该添加到您的补丁中。
    • @manlio 实际上没问题,只要我们始终为复制分配提供“最佳”重载(参见例如ericniebler.com/2013/08/07/…
    猜你喜欢
    • 2012-10-30
    • 2015-07-17
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 2015-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多