简体   繁体   中英

SIGPIPE in a simple two process program

I have a simple setup for a fork and pipe that I have used before. But this time around I'm getting a SIGPIPE in my write call. Here's the code

int fd[2];

int pid;

if (pipe(fd) == -1) {
    perror("pipe init error"); 
    exit(1);
}


// signal(SIGPIPE, SIG_IGN);
if ((pid = fork()) < -1) {
    perror("fork error"); exit(1);
}
// parent
else if (pid > 0) {
    close(fd[0]); 

    write(fd[1], "WHAT", MAXWORD); //SIGPIPE here

    close(fd[1]);
    int status;
    wait(&status);
}

// child
else {
    close(fd[1]);
    // void foo(char *dirname, int in, int out);
    // foo takes a path, reads from fd 'in' and outputs to 'fd' out
    foo("./some/path", fd[0], 1);
    close(fd[0]);
}

Here's function foo:

void foo(char *dirname, int in, int out){

    int string_length;
    char word[MAXWORD];

    // to get rid of \n
    char* sep;
    sep = malloc(sizeof(char));


    // read from piped stdin until it's closed
    while ((string_length = read(in, word, MAXWORD)) > 0){

        // get rid of \n
        sep = strchr(word, '\n');
        *sep = '\0';

        printf("THe word is: %s\n", word);

    }
}

If you get SIGPIPE when you write on a pipe, it means there is no process that can read from the pipe: neither the current process (you've close the read end of the pipe — which is good; you'd be deadlocked instead of dead if you'd not closed it) nor the other (child) process.

Since you've not shown what the function foo() does, we can't tell you any more about what's wrong.


Now that foo() has been added, it is not clear what's up. There are issues, but most are not show stoppers.

  1. Argument dirname is unused.
  2. Argument out is unused.
  3. You leak the memory allocated to sep in the loop.
  4. You do not ensure that the string read from the pipe is null terminated. This could lead to crashes, which in turn would lead to writes failing.

I suspect item 4 is the immediately critical issue; the others are more matters of tidiness.

I note that in the main code, you have:

write(fd[1], "WHAT", MAXWORD); //SIGPIPE here

Unless MAXWORD is either 4 or 5, you are on a losing path; you should only write 4 or 5 characters.

Combined with the read() ...the read will attempt to read MAXWORD bytes but might get fewer. However, there's no sign that the data written contains a newline, so the search for a newline in the input is not going to work reliably. However, that problem should manifest itself after the pipe was successfully written too, not before.

I note that the variable int fd_parent_write_word[2]; is unused and the code uses variable int fd[2] without declaring it.

It is a nuisance when what you get to analyze is not an SSCCE ( Short, Self-Contained, Correct Example ). It is so much easier when the test case has been reduced to a simple program that can be compiled and run with the submitter confident that the problem reproduces with it.


This SSCCE code compiles cleanly and runs OK:

#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

enum { MAXWORD = 5 };

static void foo(int in);

static void he_who_pays_the_piper(int signum)
{
    assert(signum == SIGPIPE);
    const char msg[] = "Received signal SIGPIPE\n";
    write(2, msg, sizeof(msg)-1);
    exit(1);
}

int main(void)
{
    int fd[2];
    int pid;

    if (pipe(fd) == -1) {
        perror("pipe init error"); 
        exit(1);
    }

    signal(SIGPIPE, he_who_pays_the_piper);
    if ((pid = fork()) < -1) {
        perror("fork error"); exit(1);
    }
    else if (pid > 0) {
        close(fd[0]); 
        write(fd[1], "WHAT", MAXWORD); //SIGPIPE here
        close(fd[1]);
        int status;
        pid = wait(&status);
        printf("Got status 0x%04X from %d\n", status, pid);
    }
    else {
        close(fd[1]);
        foo(fd[0]);
        close(fd[0]);
    }
    return 0;
}


static void foo(int in)
{
    int string_length;
    char word[MAXWORD];

    while ((string_length = read(in, word, MAXWORD)) > 0)
        printf("The word is: %.*s\n", string_length, word);
}

Example output:

The word is: WHAT
Got status 0x0000 from 49458

Note that this works because the '\\0' at the end of the string WHAT is written to the pipe, and read from the pipe. Most usually, you do not write the strings including the trailing '\\0' .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM