c++boostvalgrindboost-regex

Invalid read size 1 in valgrind using boost::smatch


I am using boost::smatch object to get the matching pattern from boost::regex_match and use that matching pattern string for further operations. It's working fine in a normal run, but when I use Valgrind for memory checking it is showing an error in the line where I am reading a match string i.e. match.str(1)

I am trying to remove this error by adding a check for the size of smatch object, but still the error occurs.

//[Modified function name because of policy]
if(boost::regex_match(arg_str,match,dcv::func_name_regex)
        && match.size() > 1) {
      std::string func_name = match.str(1);
      std::string modified_arg_str = replaceText(arg_str,func_name);

      lines.replace(
        func_lines.find(arg_str),
        arg_str.length(),
        modified_arg_str
      );
      continue;
    }

Valgrind output as:

[Modified some filename and path because of policy]
3201  ==7723== Invalid read of size 1
3202  ==7723==    at 0x517259: snps_boost_1_72_0::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::str() const (../../include/boost/regex/v4/sub_match.hpp:84)
3203  ==7723==    by 0x516205: snps_boost_1_72_0::match_results<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<snps_boost_1_72_0::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >::str(int) const (../../include/boost/regex/v4/match_results.hpp:207)
3204  ==7723==    by 0x50DDF7: Modifier::replaceText(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (/path/to/file.cpp:634)
3205  ==7723==    by 0x50D227: Modifier::functionArgument(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (/path/to/file.cpp:577)

Invalid read is on same line where matched string is read.

std::string func_name = match.str(1);

I am using gcc-7.3.0 and boost_1_72_0.


Solution

  • Kudos for unning with ASAN/UBSAN/Valgrind. You see why it is important :)

    You're reading a subgroup that wasn't successfully matched. You probably want to check that it did, the check size()>1 is NOT enough:

    Live On Coliru

    #include <boost/regex.hpp>
    #include <iostream>
    #include <iomanip>
    
    namespace dcv {
        boost::regex func_name_regex("z|(.)");
    }
    
    int main() {
        boost::smatch match;
        
        for (std::string arg_str: {"a","z"}) {
            if(boost::regex_match(arg_str, match, dcv::func_name_regex)) {
                std::cout << "Matched: " << std::quoted(arg_str) << " (" << match.size() << ")\n";
                if (match[1].matched) {
                    std::string func_name = match.str(1);
                    std::cout << "Subgroup matched: " << std::quoted(func_name) << "\n";
                } else {
                    std::cout << "Subgroup NOT matched.\n";
                }
            }
        }
    
    }
    

    Prints

    Matched: "a" (2)
    Subgroup matched: "a"
    Matched: "z" (2)
    Subgroup NOT matched.