在Ubuntu的getline上出现分段错误

segmentation fault on getline in Ubuntu

本文关键字:分段 错误 Ubuntu getline      更新时间:2023-10-16

我有著名的分割错误。我将其追踪到代码中的一行(getline)。这是一个有类似问题的人,也是在Ubuntu上:

http://www.daniweb.com/software-development/cpp/threads/329191

请注意,getline在分割错误后返回-1,但它不可能是流的真正结束(在我的例子中)。

当流较小时,一切正常。我们可以从输出中推断,分割错误出现在第98行。

     1  /* 
     2   * File:   RequestDispatcher.cpp
     3   * Author: albert
     4   * 
     5   * Created on July 8, 2011, 7:15 PM
     6   */
     7  
     8  #include "iostream"
     9  #include "fstream"
    10  #include "stdlib.h"
    11  #include "stdio.h"
    12  #include "cstring"
    13  #include "algorithm"
    14  
    15  #include "RequestDispatcher.h"
    16  #include "Functions.h"
    17  
    18  #define PROXIES 1
    19  
    20  RequestDispatcher::RequestDispatcher()
    21  {
    22  }
    23  
    24  RequestDispatcher::RequestDispatcher(const RequestDispatcher& orig)
    25  {
    26  }
    27  
    28  RequestDispatcher::~RequestDispatcher()
    29  {
    30  }
    31  
    32  int RequestDispatcher::addRequest(string host, string request, IResponseReceiver* response_receiver)
    33  {
    34      RequestInfo info;
    35      info.request_index = request_info.size();
    36      info.host = host;
    37      info.request = request;
    38      info.response_receiver = response_receiver;
    39      request_info.push_back(info);
    40      return info.request_index;
    41  }
    42  
    43  void RequestDispatcher::run()
    44  {
    45      if (request_info.size()==0)
    46      {
    47          return;
    48      }
    49      FILE* pipe[PROXIES];
    50      int per_proxy = (request_info.size() + PROXIES - 1) / PROXIES;
    51      int count_pipes = (request_info.size() + per_proxy - 1) / per_proxy;
    52      for (int pipe_index=0; pipe_index<count_pipes; ++pipe_index)
    53      {
    54          int from = pipe_index * per_proxy;
    55          int to = min(from + per_proxy, int(request_info.size()));
    56          cout << "FROM: "<< from << "; TO: " << to;
    57          const char* cmd = generateCmd(from, to);
    58          pipe[pipe_index] = popen(cmd, "r");
    59          if (!pipe[pipe_index])
    60          {
    61              cerr << "Error executing command in RequestDispatcher::run()";
    62          }
    63      }
    64      string result[PROXIES];
    65      bool finished[PROXIES];
    66      for (int pipe_index=0; pipe_index<count_pipes; pipe_index++)
    67      {
    68          finished[pipe_index] = false;
    69      }
    70      int count_finished = 0;
    71      char* buffer;
    72      size_t buffer_length=1024;
    73      buffer = (char *) malloc (buffer_length + 1);
    74      while (count_finished < count_pipes)
    75      {
    76          cout << "Dn";
    77          fflush(stdout);
    78          for(int pipe_index=0; pipe_index<count_pipes; ++pipe_index)
    79          {
    80              cout << "En";
    81              fflush(stdout);
    82              if (finished[pipe_index])
    83              {
    84                  continue;
    85              }
    86              cout << "Getline" << buffer_length << "n";
    87              ssize_t bytes_read = getline(&buffer, &buffer_length, pipe[pipe_index]);
    88              cout << "Getline Done ("<<bytes_read<< "," << buffer_length << ")n";
    89              fflush(stdout);
    90              while (bytes_read>0)
    91              {
    92                  for (int i=0; i<bytes_read; i++)
    93                  {
    94                     result[pipe_index] += buffer[i];
    95                  }
    96                  cout << "Pn";
    97                  fflush(stdout);
    98                  bytes_read = getline(&buffer, &buffer_length, pipe[pipe_index]);
    99                  cout << "Bytes read ("<<bytes_read<<","<< buffer_length << ")n";
   100                  fflush(stdout);
   101  
   102              }
   103              if (bytes_read == -1)  // then finished this pipe
   104              {
   105                  string* r = &result[pipe_index];
   106                  //cout << *r;
   107                  finished[pipe_index] = true;
   108                  ++count_finished;
   109                  cout << "HIn";
   110                  fflush(stdout);
   111                  // delete trailing '' from result
   112                  pclose(pipe[pipe_index]);
   113                  result[pipe_index] = result[pipe_index].substr(0, result[pipe_index].length()-1);
   114                  int pos = r->find("RESPONSE_DATA");
   115                  int valuepos, endvaluepos;
   116                  int request_index, length;
   117                  string headers;
   118                  int headerslength;
   119                  string body;
   120                  int bodypos, bodylength;
   121                  while (pos!=r->npos)
   122                  {
   123                      valuepos = r->find("REQUEST_INDEX=", pos) + 14;
   124                      endvaluepos = r->find("n", valuepos);
   125                      request_index = pipe_index * per_proxy + atoi(r->substr(valuepos, endvaluepos-valuepos).c_str());
   126  
   127                      cout << "REQUEST_INDEX " << request_index;
   128  
   129                      valuepos = r->find("LENGTH=", pos) + 7;
   130                      endvaluepos = r->find("n", valuepos);
   131                      length = atoi(r->substr(valuepos, endvaluepos-valuepos).c_str());
   132  
   133                      pos = r->find("START", pos)+5;
   134                      bodypos = r->find("rnrn", pos)+4;
   135                      headerslength = bodypos-pos-4;
   136                      bodylength = length-headerslength-4;
   137                      headers = r->substr(pos, headerslength);
   138                      body = r->substr(bodypos, bodylength);
   139                      request_info[request_index].response_receiver->notifyResponse(headers, body, request_index);
   140  
   141                      pos=r->find("RESPONSE_DATA", pos+length);
   142                  }
   143              }
   144          }
   145      }
   146      cout << "n?n";
   147      fflush(stdout);
   148      free(buffer);
   149      request_info.clear();
   150  }
   151  
   152  const char* RequestDispatcher::generateCmd(int first_request, int to_request)
   153  {
   154      string r("/home/albert/apachebench-standalone-read-only/ab -a");
   155      for (int i=first_request; i<to_request; i++)
   156      {
   157          r.append(" '");
   158          r.append(request_info.at(i).request);
   159          r.append("'");
   160      }
   161      ofstream out("/home/albert/apachebench-standalone-read-only/debug");
   162      if(! out)
   163      {
   164          cerr<<"Cannot open output filen";
   165          return "";
   166      }
   167      out << r.c_str();
   168      out.close();
   169      return "/home/albert/apachebench-standalone-read-only/debug";
   170      /*int size = strlen("/home/albert/apachebench-standalone-read-only/ab -a");
   171      for (int i=first_request; i<to_request; i++)
   172      {
   173          size += 2+strlen(request_info.at(i).request)+1;
   174          cout << "len: " << strlen(request_info.at(i).request) << "n";
   175          cout << "total: " << size << "n";
   176      }
   177      size += 1;
   178      char* cmd = new char[size];
   179      strcpy(cmd, "/home/albert/apachebench-standalone-read-only/ab -a");
   180      for (int i=first_request; i<to_request; i++)
   181      {
   182          cout << "LEN: " << strlen(cmd) << "n";
   183          cout << "NEXT: " << strlen(request_info.at(i).request) << "n";
   184          fflush(stdout);
   185          strcat(cmd, " '");
   186          strcat(cmd, request_info.at(i).request);
   187          strcat(cmd, "'");
   188      }
   189      cout << "LEN: " << strlen(cmd) << "n";
   190      fflush(stdout);
   191      return cmd;*/
   192  }

当我从命令行运行/home/albert/apachebench-standalone-read-only/debug时,一切都很好。返回二进制数据。

输出结束为:

P
Bytes read (272,6828)
P
Bytes read (42,6828)
P
Bytes read (464,6828)
P
Bytes read (195,6828)
P
Bytes read (355,6828)
P
Bytes read (69,6828)
P
Bytes read (111,6828)
P
Segmentation fault
Bytes read (368,6828)
P
Bytes read (-1,6828)
HI
REQUEST_INDEX 46REQUEST_INDEX 48REQUEST_INDEX 44REQUEST_INDEX 0REQUEST_INDEX 45
?

注意"?"表示退出循环。在此之后,程序结束。

顺便说一下,我一直认为程序会在段错误时终止(编辑:我没有做任何事情来捕捉它)。

对于一些答案的回答:getline似乎有不同的版本,我似乎使用这里记录的一个:

http://www.kernel.org/doc/man-pages/online/pages/man3/getline.3.html

所以经过一些思考,我认为这个问题是你的缓冲区正在被写入,因为你正在阅读它。在某些情况下,缓冲区没有完成写入,您可以从中删除一些数据(这可能意味着您可能会读取空缓冲区,因为写入尚未完成)。这是因为您正在使用popen并简单地从另一个进程输送数据。我的建议是,对于getline使用c++标准(尽管两者都有些不安全),并且在从管道读取数据时留有一些余地。重试逻辑可能是你需要的,因为我想不出一个干净的方法来解决这个问题。如果有人知道,请贴出来,我之所以贴出来,是因为我认为这可能是问题的罪魁祸首。

另外,如果你在c++中编码,我强烈建议你使用c++库,这样你就不会经常在类型之间混合或转换(例如字符串到char *等,它只是节省了一些麻烦),并且你使用更安全的版本的方法,这样你就可以避免错误,如缓冲区溢出。