std::remove_copy_if_ valgrind bytes in block are p

2019-07-16 16:24发布

问题:

Exploring a valgrind report in search of a huge memleak, it seems that the following line produces the biggest threat over lots of calls:

std::remove_copy_if(raw_word.begin(), raw_word.end(),
       std::back_inserter(word), std::ptr_fun<int, int>(&std::ispunct));

CODE

char * payload = /* acquire somehow */
int whitespace;
char * p_word = NULL;
for(whitespace = 0; whitespace < payload_len; whitespace ++)
{
  if(isspace(payload[whitespace]))
  {
    payload[whitespace] = 0;
    if(p_word != NULL)
    {
      std::string raw_word(p_word), word;
      // remove punctuation
      std::remove_copy_if(raw_word.begin(), raw_word.end(),
           std::back_inserter(word), std::ptr_fun<int, int>(&std::ispunct));
      if (/* some condition */)
      {
        // copy and consume `word`
      }
    }
    p_word = NULL;
  }
  else
  {
    if(p_word == NULL)
      p_word = payload + whitespace;
  }
}

Since I'm not very acquainted with memleak hunting, the absence of an explicit new makes me confused about the placement of a corresponding delete.

LOG

 848,631 bytes in 24,592 blocks are possibly lost in loss record 1,334 of 1,339
    at : operator new(unsigned long) (vg_replace_malloc.c:324)
    by : std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
    by : std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
    by : std::string::reserve(unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
    by : push_back (basic_string.h:1053)
    by : operator= (stl_iterator.h:440)
    by : std::back_insert_iterator<std::string> std::remove_copy_if<__gnu_cxx::__normal_iterator<char*, std::string>, std::back_insert_iterator<std::string>, std::pointer_to_unary_function<int, int> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::back_insert_iterator<std::string>, std::pointer_to_unary_function<int, int>) (stl_algo.h:951)
 // WordsSourceKafka::_do_async() contains the snipped code
    by : blockmon::WordsSourceKafka::_do_async() (WordsSourceKafka.cpp:332)
    by : blockmon::Block::run() (Block.cpp:349)
    by : operator() (ThreadHandler.hpp:149)
    by : __invoke<blockmon::ThreadHandler> (functional:235)
    by : operator()<> (functional:468)
    by : _M_invoke<> (functional:1598)
    by : operator() (functional:1586)
    by : std::thread::_Impl<std::_Bind_simple<std::reference_wrapper<blockmon::ThreadHandler> ()> >::_M_run() (thread:115)
    by : ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
    by : start_thread (pthread_create.c:304)
    by : clone (clone.S:112

回答1:

I can't tell you why, but this solved the valgrind record.

auto isPunct = [](char c)
{
    return std::ispunct(static_cast<unsigned char>(c));
};

raw_word.erase(std::remove_if(raw_word.begin(), raw_word.end(), isPunct),
               raw_word.end());