boost :: spirit :: hold_any повреждение памяти

У меня есть большая база кода, которая может использовать повышение :: любой или же повышение :: дух :: hold_any (в зависимости от определения макроса).

hold_any кажется совместимым с boost::any (например. Как распечатать boost :: any в поток? или же Тип стирания — часть IV) и быстрее (Почему вы не должны использовать 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::string в int).

Кажется странным, что в широко используемой библиотеке, такой как Boost Spirit, может быть какая-то серьезная ошибка, но

  • Мне трудно найти ошибку в примере;
  • Я пробовал g ++ / clang ++ без успеха.

Что не так с примером?

2

Решение

Вам следует не использовать hold_any как это в detail/hold_any.hpp по причине.

Это сказало, hold_anyКопирование-назначение, кажется, не работает. Я создал запрос на выгрузку на 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)
2

Другие решения


По вопросам рекламы [email protected]