I am getting a Broken Pipe error when writing a large quantity of data very fast to a C subprocess.
So I am running a c subprocess from a python script:
process = subprocess.Popen("./gpiopwm", stdin=subprocess.PIPE)
while True:
process.stdin.write("m2000\n")
print "bytes written"
Sectio of main loop of gpiopwm.c:
printf("1\n");
while (1) {
fgets(input,7,stdin); // Takes input from python script
printf("2\n");
numbers = input+1; // stores all but first char of input
char first = input[0]; // stores first char of input
if (first=='m') {
printf("3\n");
printf("%s\n",numbers);
}
}
However, the output from this is as follows:
1
bytes written
Traceback (most recent call last):
File "serial-receive-to-pwm.py", line 20, in <module>
process.stdin.write("m2000\n")
IOError: [Errno 32] Broken pipe
The C program evidently breaks at the fgets
line, as 2
is never printed.
What have I done wrong? How can I avoid this?
EDIT:
I've updated the fgets
line so that it does not include the dereference argument, but am still getting the broken pipe error.
EDIT:
input
is initialized as char *input="m2000";
If you try running your C program from the console, you will see that it crashes. And if you run in a debugger, you will see that it's on this line:
It seems like
input
is a character array, and when you dereference it with*input
you are passing not a pointer but a singlechar
value. This leads to undefined behavior and the crash.That line should have given you if not an error then a very big warning message from the compiler. Don't ignore warning messages, they are often an indicator of you doing something wrong and possibly dangerous.
A general tip: When developing a program that should be called from another program, like you do here, test the program first to make sure it works. If it doesn't work, then fix it first.
A final tip: Remember that
fgets
includes the newline in the destination string. You might want to check for it and remove it if it's there.With the last edit, showing the declaration of
input
we know the real problem: You're trying to modify constant data, and also you want to write beyond the bounds of the data as well.When you make
input
point to a literal string, you have to remember that all literal strings are read only, you can not modify a literal string. Trying to do so is undefined behavior. To make it worse, your string is only six characters long, but you try to write seven characters to it.First change the declaration and initialization of
input
:This will declare it as an array, located on the stack and that can be modified. Then do
This accomplishes two things: First by using
sizeof(input)
as the size, you can be sure thatfgets
will never write out of bounds. Secondly, by using thefgets
call in the loop condition the loop will end when the Python script is interrupted, and you won't loop forever failing to read anything and then work on data that you've never read.