添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I've got a C program that reproduces a server using FIFOs. The program reads two lines from an input FIFO — a number n and a string str — and writes on an output FIFO n lines, each of which is a single occurrence of str . I wrote the following code.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define MAX_SIZE 256
char *readline(int fd, char *buffer) {
    char c;
    int i = 0;
    while (read(fd, &c, 1) != 0) {
        if (c == '\n')
            break;
        buffer[i++] = c;
    return buffer;
int main(int  argc, char** argv) {
    mkfifo(argv[1], 0666);
    mkfifo(argv[2], 0666);
    int in = open(argv[1], O_RDONLY);
    int out = open(argv[2] ,O_WRONLY);
    char line[MAX_SIZE];
    memset(line, 0, MAX_SIZE);
    int n, i;
    while (1) {
        strcpy(line, readline(in, line));
        sscanf(line, "%d", &n);
        strcpy(line, readline(in, line));
        for (i = 0; i < n; i++) {
            write(out, line, strlen(line));
            write(out, "\n", 1);
    close(in);
    close(out);
    return 0;

This program compiles and runs with no errors, but it outputs a different number of occurrences of the string at each execution. For example, if the two input lines in the input FIFO are 5\nhello, it then prints out from 1 to 25 occurrences of hello at each run (frequency appears to be completely random).

I've been stuck on this for two days. Please give me some help.

The strcpy in strcpy(readline(in, line)) seems useless. More to the point: have you tried just printing n? You're also not checking the return value from sscanf for errors. – Fred Foo Nov 10, 2013 at 13:25 Its not just useless, since readline() returns the passed buffer as the result. The buffer's submitted to strcpy() cannot overlap. If they do, it is undefined behavior. In this case they not only overlap, they are the same buffer. – WhozCraig Nov 10, 2013 at 13:55

I make no claims or warrants that I even know what your program does, as it has been 20 years since I had any pressing need to work with FIFO's at the system level. But one thing is clear. Two days is a long time to work on something without ever running it in a debugger, of which doing so would have exposed a number of problems.

First, readline() never terminates the string it is passed. This isn't as important the first time around as the second and beyond, since shorter data may be present in the input lines. Furthermore, read() can fail, and in doing so does not return 0, the only condition on your loop which will break. That failure should break the loop and be reflected in the return result. Because you return the buffer pointer, a reasonable failure-result could be NULL:

Consider something like this:

char *readline(int fd, char *buffer)
    ssize_t res = 0;
    char c = 0;
    int i = 0;
    for(;;)
        res = read(fd, &c, 1);
        if (res < 0)
            return NULL;
        else if (res == 0 || c == '\n')
            break;
        buffer[i++] = c;
    buffer[i] = 0;
    return buffer;

One could argue that it should return NULL if the buffer is empty, since you can't put a 0-length packet on a FIFO. I leave that for you to decide, but it is a potential hole in your algorithm, to be sure.

Next the strcpy() function has undefined behavior if the buffers submitted overlap. Since readline() returns the very buffer that was passed in, and since said-same buffer is also the target of strcpy() is the same buffer, your program is executing UB. From all that I see, strcpy() is useless in this program in the first place, and shouldn't even be there at all.

This is clearly wrong:

strcpy(line, readline(in, line));
sscanf(line, "%d", &n);
strcpy(line, readline(in, line));
for (i = 0; i < n; i++) {
    write(out, line, strlen(line));
    write(out, "\n", 1);

The above should be this:

if (readline(in, line))
    if (sscanf(line, "%d", &n) == 1)
        if (readline(in, line))
            for (i = 0; i < n; i++) 
                write(out, line, strlen(line));
                write(out, "\n", 1);

assuming the changes to readline() as prescribed were made. These could be combined into a single three-expression if-clause, but as written above it is at-least debuggable. In other words, via short-circuit eval there should be no problems doing this:

if (readline(in, line) &&
    sscanf(line, "%d", &n) == 1 &&
    readline(in, line))
    for (i = 0; i < n; i++) 
        write(out, line, strlen(line));
        write(out, "\n", 1);

but I would advise you keep the former until you have thoroughly debugged this.

Finally, note that readline() is still a buffer overflow just waiting to happen. You really should pass a max-len to that function and limit that potential possibility, or dynamically manage the buffer.

@alk if you're referring to returning (-1) due to signals, etc, I concur, but I didn't include it because you already did. I really should edit this and throw that in there. – WhozCraig Nov 10, 2013 at 14:14

The code does not initalises line for each iteration, so if readline() does not read anything it leaves line's content untouched.

And you do not test whether sscanf() fails, the code does not recognize als n is left unchanged and the last value of line get printed out n times and everything starts over again ...

Also readline() misses to check whether read() failed.

To learn from this exercise it to always test the result of a (system) call whether it failed or not.

int readline(int fd, char *buf, int nbytes) {
   int numread = 0;
   int value; /* read fonksiyonu sonunda okunan sayı degerini gore islem yapar */
   /* Controls  */
   while (numread < nbytes - 1) {
      value = read(fd, buf + numread, 1);
      if ((value == -1) && (errno == EINTR))
         continue;
      if ( (value == 0) && (numread == 0) )
         return 0;
      if (value == 0)
         break;
      if (value == -1)
         return -1;
      numread++;
      /* realocating for expand the buffer ...*/
      if( numread == allocSize-2 ){
         allocSize*=2;   /* allocSize yeterli olmadıgı zaman buf ı genisletmemizi saglayarak
         memory leak i onler  */
         buf=realloc(buf,allocSize);
         if( buf == NULL ){
           fprintf(stderr,"Failed to reallocate!\n");
             return -1; 
      /* Eger gelen karakter \n ise return okudugu karakter sayısı */
      if (buf[numread-1] == '\n') {
          buf[numread] = '\0';
          return numread; 
   errno = EINVAL;
   return -1;   
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.