Skip to content

Instantly share code, notes, and snippets.

@ScottDuckworth
Created March 24, 2014 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ScottDuckworth/9745307 to your computer and use it in GitHub Desktop.
Save ScottDuckworth/9745307 to your computer and use it in GitHub Desktop.
Demonstrate how deadlock can occur with bi-directional process communication via pipes
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUF_SIZE ((size_t)(10<<20)) /* 10 MiB */
int main() {
pid_t pid;
int rc, pipe_to_child[2], pipe_to_parent[2];
size_t n;
FILE *to_child, *to_parent;
char *buf;
buf = calloc(BUF_SIZE, 1);
rc = pipe(pipe_to_child);
if(rc) {
perror("pipe");
exit(1);
}
rc = pipe(pipe_to_parent);
if(rc) {
perror("pipe");
exit(1);
}
pid = fork();
if(pid == -1) { /* error */
perror("fork");
exit(1);
} else if(pid == 0) { /* child */
close(pipe_to_child[1]);
close(pipe_to_parent[0]);
to_child = fdopen(pipe_to_child[0], "rb");
if(!to_child) {
perror("fdopen child to_child");
exit(1);
}
to_parent = fdopen(pipe_to_parent[1], "wb");
if(!to_parent) {
perror("fdopen child to_parent");
exit(1);
}
/* Simulates performing a partial read of the key that would be sent to
* the AuthorizedKeysCommand.
*/
printf("child reading up to 8 bytes\n");
n = fread(buf, 1, 8, to_child);
printf("child read %lu bytes\n", n);
/* Simulates returning a large set of public keys to sshd.
*/
printf("child writing %lu bytes\n", BUF_SIZE);
n = fwrite(buf, 1, BUF_SIZE, to_parent);
/* DEADLOCK: We never get to this point because the parent is still trying
* to write data to to_child, but we're never reading that data.
*/
printf("child wrote %lu bytes\n", n);
exit(0);
} else { /* parent */
close(pipe_to_child[0]);
close(pipe_to_parent[1]);
to_child = fdopen(pipe_to_child[1], "wb");
if(!to_child) {
perror("fdopen parent to_child");
exit(1);
}
to_parent = fdopen(pipe_to_parent[0], "rb");
if(!to_parent) {
perror("fdopen parent to_parent");
exit(1);
}
/* Simulates sending an unusually large public key (perhaps one that is
* fabricated) to the child process.
*/
printf("parent writing %lu bytes\n", BUF_SIZE);
n = fwrite(buf, 1, BUF_SIZE, to_child);
/* DEADLOCK: We never get to this point since the child is not reading the
* other end of this pipe, nor will it close the other end of the pipe
* because it was not explicitly closed and the process will not exit
* because it too is blocked.
*/
printf("parent wrote %lu bytes\n", n);
fclose(to_child);
/* Simulates reading the public keys from AuthorizedKeysCommand.
*/
printf("child reading up to %lu bytes\n", BUF_SIZE);
n = fread(buf, 1, BUF_SIZE, to_parent);
printf("parent read %lu bytes\n", n);
wait(&rc);
exit(rc);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment