ошибка сегментации на getline в Ubuntu

У меня знаменитая ошибка сегментации. Я отследил его до одной строки кода (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 << "D\n";
    77          fflush(stdout);
    78          for(int pipe_index=0; pipe_index<count_pipes; ++pipe_index)
    79          {
    80              cout << "E\n";
    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 << "P\n";
    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 << "HI\n";
   110                  fflush(stdout);
   111                  // delete trailing '\0' 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("\r\n\r\n", 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 file\n";
   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


person Albert Hendriks    schedule 17.07.2011    source источник
comment
Большинство программ завершаются на SIGSEGV. Может быть, у вас есть обработчик сигналов, настроенный на его перехват?   -  person John Zwinck    schedule 17.07.2011
comment
stdlib.h и stdio.h устарели в C++. Используйте cstdlib и cstdio или, что предпочтительнее, не используйте их вообще. Затем запустите код через отладчик. Зачем смешивать код в стиле C и C++? Кроме того, пожалуйста, оставьте номера строк вне вставки вашего кода: это действительно неприятно заставлять меня редактировать их вручную, если я хочу попробовать вашу программу! .... чего я все равно не могу сделать, потому что это не тестовый пример.   -  person Lightness Races in Orbit    schedule 17.07.2011
comment
@Джон, спасибо за прояснение, похоже, у него утечка памяти, потому что GNU getline уже выделяет память для вашего char *buffer, я прав?   -  person Jesus Ramos    schedule 17.07.2011
comment
@Jesus: при определенных условиях. Конечно, утечки памяти не вызывают сбоев.   -  person Lightness Races in Orbit    schedule 17.07.2011
comment
Может быть, я предполагаю, что канал все еще записывается, пока вы его читаете.   -  person Jesus Ramos    schedule 17.07.2011
comment
@ Господи, это, конечно, правда. Я предполагаю, что чтение не ждет автоматически тогда ..?   -  person Albert Hendriks    schedule 17.07.2011
comment
@Albert no read по умолчанию не ждет, он читает то, что в данный момент находится в буфере. Я видел, как это случалось много раз раньше, когда файлы записывались и читались одновременно, когда строки обрезались, потому что буфер еще не был полностью очищен.   -  person Jesus Ramos    schedule 17.07.2011
comment
@Tomalak Какие библиотеки мне тогда использовать? +1 Я нашел кнопку отладки. Я все еще изучаю различия между C и C++. В следующий раз я оставлю номера строк и создам тестовый пример.   -  person Albert Hendriks    schedule 17.07.2011
comment
@Albert: все возможности, предоставляемые стандартной библиотекой C++. vector, потоки (которые вы уже используете только наполовину) и передавайте std::string, а не char const*! Комментарии к коду тоже не помешают.   -  person Lightness Races in Orbit    schedule 17.07.2011


Ответы (1)


Итак, после некоторых размышлений, я считаю, что проблема заключается в том, что ваш буфер записывается, когда вы его читаете. В некоторых случаях запись в буфер не завершена, и вы удаляете из него некоторые данные (что может означать, что вы можете прочитать пустой буфер, потому что запись не выполнена). Это потому, что вы используете popen и просто передаете данные из другого процесса. Что я бы порекомендовал, так это то, что для одного из них вы используете стандарт C++ для getline (хотя оба они несколько небезопасны) и что у вас есть некоторая свобода действий для чтения данных из канала. Логика повторения может быть тем, что вам нужно, поскольку я не могу придумать чистый способ решить эту проблему. Если кто-нибудь знает, пожалуйста, напишите об этом, я публикую это, потому что это то, что я считаю вероятным виновником проблемы.

Кроме того, если вы пишете код на С++, я настоятельно рекомендую вам использовать библиотеки С++, чтобы вы не смешивали или не приводили постоянно типы между типами (например, строку в char * и т. д., это просто избавляет вас от некоторых хлопот) и что вы используете более безопасные версии методов, чтобы избежать таких ошибок, как переполнение буфера.

person Jesus Ramos    schedule 17.07.2011
comment
@Als Я по ошибке нажал Enter после табуляции и не закончил вводить ответ - person Jesus Ramos; 17.07.2011
comment
Вы думаете о getline стандартной библиотеки C++, тогда как OP использует этот: linux.die .net/man/3/getline - person John Zwinck; 17.07.2011
comment
@Джон, спасибо, что прояснил это, я видел код С++ и предположил, что он использует стандарт С++. - person Jesus Ramos; 17.07.2011
comment
Это действительно было так. Сейчас я использую PStreams, и это работает. - person Albert Hendriks; 17.07.2011
comment
@Albert, рад, что смог помочь, в библиотеке C++ обычно есть решение: D - person Jesus Ramos; 17.07.2011