管道覆盖缓冲区,不知道如何克服

时间:2012-06-08 04:36:51

标签: c fork pipe

我使用简单的管道。我读了一会儿,一次一个字符,我想我每次读一个字母都会覆盖一些东西

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main () {
    int pipefd[2];
    int cpid;
    char buf[31];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    cpid = fork();
    if (cpid == -1) {
        perror("cpid");
        exit(EXIT_FAILURE);
    }
    if (cpid == 0) {      // child reads from pipe
        close (pipefd[1]); // close unused write end
        int i = 0;
        while (read (pipefd[0], &(buf[i++]), 1)>0);
        printf ("Server receives: %s", buf);
        close (pipefd[0]);
        exit (EXIT_SUCCESS);
    }
    else {               // parent writes to pipe
        close (pipefd[0]); // closing unused read end;
        char buf2[30];
        printf("Server transmits: ");
        scanf ("%s", buf2);
        write (pipefd[1], buf2, strlen(buf2)+1);
        close(pipefd[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);
    }
  return 0;
}

现在修复了代码,这已经过时了:例如,如果我输入:“Flowers”,它会打印F然后打印~6个不可打印的字符

BUT:正在发生的一件奇怪的事情,我只是使用了超过30的字符串方式,并且它根本没有产生任何错误,它确实设法写出整个字符串。虽然我的缓冲区都比这个要小得多。

2 个答案:

答案 0 :(得分:1)

这里看起来不对

while (read (pipefd[0], &buf, 1)>0);

你一遍又一遍地读一个字符到缓冲区的第一个位置

相反,您应该增加放置读取字符的位置

e.g。

int i = 0;
while (read(pipefd[0], buf + i, 1) >0 ) ++i;
buf[i] = 0; // end string

也许还可以检查不会大于buf大小。

while (read(pipefd[0], buf + i, 1) >0 && i < sizeof(buf)) ++i;

答案 1 :(得分:1)

(按照安德斯的建议。)

使用GCC 4.6.3,我的代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main () {
    int pipefd[2];
    int cpid;
    char buf[31];
    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }
    cpid = fork();
    if (cpid == -1)
    {
        perror("cpid");
        exit(EXIT_FAILURE);
    }
    if (cpid == 0) {      // child reads from pipe
        close (pipefd[1]); // close unused write end
        int i=0;
        while (read(pipefd[0], &(buf[i++]), 1) != 0);
        printf ("Server receives: %s\n", buf);
        close (pipefd[0]);
        exit (EXIT_SUCCESS);
    }
    else {               // parent writes to pipe
        close (pipefd[0]); // closing unused read end;
        char buf2[30];
        printf("Server transmits: ");
        scanf ("%s", buf2);
        write (pipefd[1], buf2, strlen(buf2)+1);
        close(pipefd[1]);
        wait(NULL);
        exit(EXIT_SUCCESS);
    }
  return 0;
}

产地:

[user@host tmp]$ gcc pipes.c -o pipes && ./pipes 
Server transmits: Flowers
Server receives: Flowers

(我也同意他对边界检查的看法。)


编辑:根据您的评论,如果您更改以下行(35为我)

scanf("%s", buf2);

fgets(buf2, 30, stdin);

你获得两项福利。 (a)通过限制将复制到buf2的字节数来消除缓冲区溢出漏洞。 (b)您可以“接受”非换行空格(空格和制表符),而使用scanf则不是:

[user@host tmp]$ gcc pipes.c -o pipes && ./pipes 
Server transmits: Flowers smell nice
Server receives: Flowers smell nice