Ошибка сегментации регулярного выражения - PullRequest
0 голосов
/ 28 мая 2019

У меня есть регулярное выражение, которое выдает ошибку segmentation fault. После некоторых тестов я заметил, что [\s\S]*\s+ часть регулярных выражений создает проблемы, если строка больше 15 КБ, поэтому иногда это работает, но иногда происходит сбой.

Вот код C ++, скомпилированный с g ++ (gcc v. 6.3.0)

#include <regex>
#include <fstream>
#include <string>
#include <iostream>

int main (int argc, char *argv[]) {

    std::regex regex(
            R"([\s\S]*\s+)",
            std::regex_constants::icase
    );

    std::ifstream ifs("/home/input.txt");
    const std::string input(
            (std::istreambuf_iterator<char>(ifs)),
            (std::istreambuf_iterator<char>())
            );

    std::cout << "input size: " << input.size() << std::endl;

    bool reg_match = std::regex_match(input, regex);

    std::cout << "matched: " << reg_match << std::endl;

}

Что происходит, почему это происходит с таким шаблоном и почему на него влияет размер ввода?

UPDATE:

Ошибка при запуске двоичного файла при компиляции с -fsanitize = address:

g ++ -std = c ++ 11 /home/app/src/test.cpp -o / home / app / bin / test -fsanitize = address

ASAN:DEADLYSIGNAL
=================================================================
==37041==ERROR: AddressSanitizer: stack-overflow on address 0x7ffbff8edff8 (pc 0x55afae25781b bp 0x7ffbff8ee010 sp 0x7ffbff8edff0 T0)
    #0 0x55afae25781a in bool __gnu_cxx::operator==<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&) (/home/app/bin/test+0x1981a)
    #1 0x55afae2587bd in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_dfs(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) (/home/app/bin/test+0x1a7bd)
    #2 0x55afae25e2d2 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_rep_once_more(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) (/home/app/bin/test+0x202d2)
.
.
.
 #251 0x55afae25e2d2 in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_rep_once_more(std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_Match_mode, long) (/home/app/bin/test+0x202d2)

SUMMARY: AddressSanitizer: stack-overflow (/home/app/bin/test) in std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std:__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*,std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_dfs(std::__detail::_Executo<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::submatch<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_trats<char>, true>::_Match_mode, long)
    ==37017==ABORTING

1 Ответ

0 голосов
/ 28 мая 2019

У меня нет полного ответа, но по какой-то причине происходит переполнение стека при сопоставлении вашего регулярного выражения. Обычно это вызвано либо слишком большим объемом данных в стеке, либо слишком большим количеством уровней рекурсии. Глядя на вашу программу, я не вижу больших объектов в стеке (строковый объект в стеке мал, поскольку его данные находятся в куче). Тем не менее, конечные автоматы, используемые для разбора регулярных выражений, известны тем, что они выполняют много рекурсивных вызовов функций (это совпадает с вашим длинным выводом Address Sanitizer). У вас есть несколько вариантов (я бы попробовал их в таком порядке):

  • Убедитесь, что вы компилируете с соответствующим уровнем оптимизации. На более высоких уровнях оптимизации компиляторы часто помещают меньше стеков в стек (см. « оптимизация хвостового вызова »).
  • Попробуйте передать std::regex_constants::optimize, чтобы заставить код регулярного выражения занимать больше времени для оптимизации при создании конечного автомата для обработки регулярного выражения.
  • Переосмыслите свое регулярное выражение. Может быть, вы можете упростить его таким образом, чтобы конечный автомат работал с меньшим количеством уровней рекурсии? [\s\S]* часть выглядит немного нетрадиционно.
  • Измените вашу программу для обработки входных данных небольшими порциями, например, построчно.
  • Увеличьте размер своего стека. В системах POSIX вы можете сделать это, позвонив ulimit -s <stack size in kB> перед запуском вашей программы.
  • Рассмотрите возможность компиляции вашей программы с автоматически растущими стеками (-fsplit-stacks) . Обратите внимание, что это происходит за счет некоторой производительности.
...