Как предотвратить переполнение буфера в C / C ++? - PullRequest
3 голосов
/ 12 января 2011

Я использую следующий код, чтобы перенаправить стандартный вывод в канал, а затем прочитать все данные из канала в буфер.У меня 2 проблемы:

первая проблема: когда я отправляю строку (после перенаправления) больше, чем BUFF_SIZE канала, программа перестает отвечать (тупик или что-то).

вторая проблема: , когда я пытаюсь прочитать из канала, прежде чем что-то было отправлено на стандартный вывод.Я получаю тот же ответ, программа перестает отвечать - _read команда застряла ...

Проблема в том, что я не знаю объем данных, которые будут отправлены в канал после перенаправления.

Первая проблема, я не знаю, как справиться, и я буду рад за помощь.Вторая проблема, которую я решил простым обходным путем, сразу после перенаправления я печатаю символ пробела в стандартный вывод.но я думаю, что это решение не является правильным ...

#include <fcntl.h>
#include <io.h>
#include <iostream>

#define READ 0
#define WRITE 1
#define BUFF_SIZE 5

using namespace std;

int main()
{

  int stdout_pipe[2];
  int saved_stdout;

  saved_stdout = _dup(_fileno(stdout));            // save stdout 

  if(_pipe(stdout_pipe,BUFF_SIZE, O_TEXT) != 0 )   // make a pipe
  {    
    exit(1);
  }

  fflush( stdout );

  if(_dup2(stdout_pipe[1], _fileno(stdout)) != 0 ) //redirect stdout to the pipe 
  { 
    exit(1);
  }

  ios::sync_with_stdio();    
  setvbuf( stdout, NULL, _IONBF, 0 );

  //anything sent to stdout goes now to the pipe
  //printf(" ");//workaround for the second problem

  printf("123456");//first problem

  char buffer[BUFF_SIZE] = {0};
  int nOutRead = 0;
  nOutRead = _read(stdout_pipe[READ], buffer, BUFF_SIZE); //second problem
  buffer[nOutRead] = '\0';

  // reconnect stdout

  if (_dup2(saved_stdout, _fileno(stdout)) != 0 ) 
  {        
         exit(1);
  }
  ios::sync_with_stdio();

  printf("buffer: %s\n", buffer);
  }

Ответы [ 3 ]

1 голос
/ 12 января 2011

Ваша проблема в том, что вы используете блокировку вызовов ввода / вывода, в то время как оба конца канала подключены к одному и тому же процессу.Если вы не знаете, сколько данных будет, это просто тупиковая ситуация, ожидающая возникновения.

printf - это блокирующий вызов, который означает, что он не вернется, пока все данные не будут записанына устройство вывода (в данном случае это канал) или пока не будет сообщено об ошибке записи (например, другой конец канала закрыт).
_read работает аналогично.Он возвращается только тогда, когда у него есть полный буфер данных, или он знает, что конец ввода достигнут (о чем можно сообщить, закрыв конец записи канала).

Единственные способы обойтиэто

  • для использования неблокирующего ввода-вывода (что невозможно, если у вас нет доступа к коду, вызывающему printf), или
  • для обеспечениячтение и запись происходят в разных процессах или потоках, или
  • для использования временного файла для буферизации вместо буфера канала.
1 голос
/ 12 января 2011

Трубы однонаправленные.То есть.Вы можете написать в канал (x) или прочитать из него.

Чтобы смоделировать конвейер, попробуйте следующее (ниже C, а не C ++):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc)
{
    int pfds[2];

    pipe(pfds);

    if (!fork()) {
        close(1);       /* close stdout, check for errors */
        dup(pfds[1]);   /* make stdout same as pfds[1], dup reuses lowest fd */
        close(pfds[0]); /* not needed */
        execlp("ls", "ls", NULL); /* or write() in whatever way you want */
    } else {
        close(0);       /* close stdin, check for errors please! */
        dup(pfds[0]);   /* make stdin same as pfds[0] */
        close(pfds[1]); /* not needed on this end */
        execlp("wc", "wc", "-l", NULL); /* or read() */
    }

    return 0;
}

[править] Кстати, ваш код не переполняет буфер.Его единственное отношение к переполнению буфера состоит в том, что вы читаете в статически размещенный массив ... если вы read() больше, чем sizeof buffer элементов, то у вас возникнут проблемы.

0 голосов
/ 12 января 2011

Вы должны использовать неблокирующий ввод / вывод, если вы не хотите, чтобы чтение или запись были заблокированы в этом случае.

...