如何防止C / C ++中的缓冲区溢出?

时间:2011-01-12 10:49:57

标签: c++ redirect pipe

我使用以下代码将stdout重定向到管道,然后将管道中的所有数据读取到缓冲区。我有两个问题:

第一个问题:当我发送一个字符串(重定向后)大于管道的BUFF_SIZE时,程序停止响应(死锁或其他)。

第二个问题:当我尝试在将某些内容发送到stdout之前从管道中读取时。我得到相同的响应,程序停止响应 - _read命令卡住了......

问题是我不知道重定向后将发送到管道的数据量。

第一个问题,我不知道如何处理,我会很乐意提供帮助。我通过简单的解决方法解决了第二个问题,在重定向后我将空格字符打印到stdout。但我想这个解决方案不是正确的......

#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 个答案:

答案 0 :(得分:1)

您的问题是您正在使用阻止I / O调用,而管道的两端都连接到同一进程。如果您不知道将会有多少数据,这只是一个等待发生的死锁情况。

printf是一个阻塞调用,这意味着它不会返回,直到所有数据都写入输出设备(在这种情况下为管道),或者直到发出写入错误信号为止(例如,管道的另一端是关闭的。) _read的工作方式类似。它仅在具有完整缓冲区数据的情况下返回,或者它知道已到达输入的结尾(可以通过关闭管道的写入端来发出信号)。

解决这个问题的唯一方法是

  • 使用非阻塞I / O(如果您无权访问调用printf的代码,则不可行)或
  • 确保读取和写入在不同的进程或线程中发生,或
  • 使用临时文件进行缓冲,而不是使用管道的缓冲区。

答案 1 :(得分:1)

管道是单向的。 IE浏览器。您可以写入管道(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个元素,那么你就会遇到问题。

答案 2 :(得分:0)

如果您不希望在这种情况下阻止读取或写入,则必须使用非阻塞I / O.