检测并修复C++中的堆损坏

Detecting and fixing heap corruption in C++

本文关键字:损坏 C++ 检测      更新时间:2023-10-16

我在(win32)C++应用程序中遇到堆损坏问题。在代码中插入_heapch()之后,我设法缩小了原因。应用程序运行;然而,它"不时"崩溃。这是代码:

void parse_config(void) {
     int *regex_d;                  // regex data parsed fields(from a line from config_file)
     vector<string> input_fields;            // filtered data
     ifstream file(param.topology_file.c_str());// open file for input
     ifstream reg_file(param.regex_file.c_str());   // open the regex file and read contents(all content is placed on a single line -- no new line characters allowed)
     if(reg_file.is_open())
     {
      // read regex content into the string regex variable 
      param.regex.assign((istreambuf_iterator<char>(reg_file)), istreambuf_iterator<char>()); 
      reg_file.close();
     }
     split_regex();                     
     string buff;                       // store contents of input file
     string::const_iterator start, end;
     int temp, temp1, temp2;
     int n_of_fields = 0;            // number of fields found in an input line
     const size_t l = 10;           // number of digits each data field has
     for(unsigned i = 0; i < strlen(topology_component); i++)
     {
         if(topology_component[i] == ':')
             n_of_fields++;
     }
     input_fields.resize(n_of_fields);
     regex_d = new int[n_of_fields]; 
     for(vector<string>::iterator iter = input_fields.begin(); iter != input_fields.end(); iter++) 
     {
        (*iter).reserve(l);
     } 
      if (file.is_open())
      {
         file.seekg(0, ios::end);   
         buff.reserve(file.tellg());
         file.seekg(0, ios::beg);
         buff.assign((istreambuf_iterator<char>(file)), istreambuf_iterator<char>()); // read contents of file in buff
         file.close();
         boost::regex expression(topology_component);
         boost::match_results<string::const_iterator> m_res; 
         boost::match_flag_type flags = boost::match_default;
         start = buff.begin();
         end = buff.end();
         // searching the buffer for valid entries 
         while(boost::regex_search(start, end, m_res, expression, flags))
         {
             start = m_res[0].second;
             flags |= boost::match_prev_avail;
             flags |= boost::match_not_bob;
             int i = 1;
             for(vector<string>::iterator iter = input_fields.begin(); iter != input_fields.end(); iter++, i++)
             {
                (*iter).erase();
                (*iter).append(m_res[i]);
                sscanf((*iter).c_str(), "%d", &regex_d[i]);     
             }
                         ...
          }
      n_of_fields = 0;
      for(unsigned i = 0; i < strlen(routing_component); i++)
      {
         if(routing_component[i] == ':')
              n_of_fields++;
      }
      delete[] regex_d;
      regex_d = NULL;
      input_fields.resize(n_of_fields);
      regex_d = new int[n_of_fields];
      for(vector<string>::iterator iter = input_fields.begin(); iter != input_fields.end(); iter++) // allocate memory
      {
           iter->reserve(l);
      }
      boost::regex expression(routing_component);
      boost::match_results<string::const_iterator> m_res; 
      boost::match_flag_type flags = boost::match_default;
      start = buff.begin();
      end = buff.end();
      // searching the buffer for valid entries 
      // rtable_cur:0 rtable_dst:0 rtable_nxt:0 rtable_vc:0
      while(boost::regex_search(start, end, m_res, expression, flags))
      {
          start = m_res[0].second;
          flags |= boost::match_prev_avail;
          flags |= boost::match_not_bob;
          // parse one line from config file
          int i = 1;
          for(vector<string>::iterator iter = input_fields.begin(); iter != input_fields.end(); iter++, i++)
          {
              (*iter).erase();   // <== HEAP CORRUPTION OCCURS HERE
              (*iter).append(m_res[i]); // <== HEAP CORRUPTION
              sscanf((*iter).c_str(), "%d", &regex_d[i]); // <== HEAP CORRUPTION
          }
            ...
      }
       ...
   }

当我尝试重用input_fields向量时,堆在整个程序中都会损坏。param是一个容器,其中包含经过验证的用户输入。split_regex()方法用于获得两个字符串:topology_component和routing_component。两者都属于char*类型。

     void split_regex(void) // regex is of type "topology_component|routing_component"
     {
      bool split = false;
      unsigned i, j = 0;
      if(topology_component == NULL)
      {
          topology_component = (char*)malloc(REGEX_SIZE);
      }
      if(routing_component == NULL)
      {
          routing_component = (char*)malloc(REGEX_SIZE);
      }
      for(i = 0; i < param.regex.size(); i++)
      {
         if(split == false)
         {
             if(param.regex.at(i) == '|')
             {
                 split = true;
                 j = 0;
                 continue;
             }
             topology_component[i] = param.regex[i];
          }
          else
          {
             topology_component[i-1] = '';
             routing_component[j++] = param.regex[i];
          }
      }
    routing_component[j] = '';
   }

assert(_CrtCheckMemory())非常适合检测内存泄漏。把它放在代码的各个地方,它将帮助你缩小问题的范围。您的应用程序必须使用调试配置生成。此外,它可能会减慢执行速度。

代码可能正在写入regex_d数组的末尾。在一些地方,有一段代码将i = 1;赋值,然后在regex_d中执行scanf。我怀疑它应该从零开始:

         int i = 1;  <== should be 0?
         for(vector<string>::iterator iter = input_fields.begin(); iter != input_fields.end(); iter++, i++)
         {
            <snip>
            sscanf((*iter).c_str(), "%d", &regex_d[i]);     

此外,该循环似乎应该进行检查,以验证其增量是否超过regex_d的原始分配大小。