Standard Buffer not getting cleared before system() call - c

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void handler(int signo)
{
printf("First statement");
system("date");
exit(EXIT_SUCCESS);
}
int main()
{
signal(SIGINT,handler);
printf("Waiting for KeyboardInterrupt\n");
for(;;);
return 0;
}
Test run:-
shadyabhi#shadyabhi-desktop:~/c$ gcc main.c
shadyabhi#shadyabhi-desktop:~/c$ ./a.out
Waiting for KeyboardInterrupt
^CWed Mar 10 23:55:47 IST 2010
First statementshadyabhi#shadyabhi-desktop:~/c$
Why is "First Statement" getting printed after system() call??

The standard input, output and error streams are created when your process starts, which in this case is your C program. When you make the system call, another process is created to execute the date command, and it gets its own set of streams.
In your program, the printf output is buffered to the standard output stream of your C program. Then the output of date is buffered to its own standard output stream. When the system call ends, the date standard output stream is flushed, so you see the output. Then, when your C program ends, its standard output stream is flushed and you see the printf output.
You might find this fellow's posting helpful: http://www.pixelbeat.org/programming/stdio_buffering/

Did you try flushing the buffer before calling system("date")?
I just added fflush(NULL); before system, and the output is as expected.

The C IO API buffers things up in order to print more efficiently. Typically the buffer is flushed whenever you write out a newline or manually flush it.
So you can use a newline to flush the buffer:
printf("First statement\n");
Or use the fflush function:
printf("First statement");
fflush (stdout);

Related

Forking code creates unexpected results when redirecting output to file [duplicate]

This question already has answers here:
printf anomaly after "fork()"
(3 answers)
fork() branches more than expected?
(3 answers)
Closed last year.
I have the following C code:
#include <stdio.h>
#include <unistd.h>
int main()
{
int i, pid = 0;
for (i = 0; i < 3; i++)
{
fork();
pid = getpid();
printf("i=%d pid=%d\n", i, pid);
}
return 1;
}
Which is supposed to create a total of 7 new processes after all the iterations in the loop. Analyzing it you can see that 14 lines should be printed before all the processes finish, and that is exactly what you see when you execute it from the command line.
However, when you redirect the output to another file ./main > output.txt; cat output.txt, you get a completely different situation. In total, 24 lines are always printed and some of them are repeated for the same i and pid values, and the amount of repetition seems consistent. I'm attaching a screenshot for clarification here Execution example. The system that I'm using is Ubuntu 20.04.3 in a VirtualBox VM.
I really don't understand why that is happening, I'm guessing it has something to do with race conditions on the output buffer or some other conflict when multiple processes are writing to the file, but that doesn't explain to me why it doesn't happen on the terminal. Can anybody explain this odd behaviour? Thanks!
When the standard output is a terminal, the stream is typically line buffered. The C standard requires it not be fully buffered, meaning it must be line buffered or unbuffered; C 2018 7.21.3 6 says:
… As initially opened, … the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
When the program executes printf("i=%d pid=%d\n", i, pid);, the output is immediately sent to the terminal, either because the stream is line buffered and the new-line character causes the output to be sent or because the stream is unbuffered and the output is always sent in each printf. Then, when the program forks, there is no pending output, because it has already been sent to the terminal. Each forked instance of the program prints only its own output.
When the standard output is redirected to a file, the stream is fully buffered. Then, when the program executes printf("i=%d pid=%d\n", i, pid);, the data is held in a buffer inside the program. It is not sent to the terminal immediately. (It will be sent when the buffer is full or when a flush is requested, which occurs automatically at normal program termination.) When the program forks, the buffer is copied along with the rest of the program state. Each forked instance of the program accumulates output in the buffer.
When each forked instance of the program exits, pending data in its buffers are flushed. Thus includes both data added by that particular instance and data that was put into the buffer in parent processes and copied by the fork. Thus multiple copies of data are printed.
To resolve this, execute fflush(stdout); immediately before fork();. This flushes the buffer before forking. Alternately, request that the stream be line-buffered by executing setvbuf(stdout, NULL, _IOLBF, 0); at the start of main.

Unexpected output on a fork call in C [duplicate]

This question already has answers here:
Why is main called twice?
(3 answers)
Closed 1 year ago.
I encountered this in my school work and it didn't produce what I thought it should:
int main() {
printf("c");
fork();
printf("d");
}
I know there are several things that aren't good about this code (i.e. no parameters in main, no variable for the return value from fork, no return statement at the end, etc.), but this is how it was presented and it's not relevant to my question anyway.
This code produces the output:
cdcd
It was my understanding that when fork is called, both parent and child would resume/begin on the line after the fork call. Based on that, I would have expected the output to be:
cdd
Assuming, of course, that the fork call is successful. Can anyone explain to me why that "c" is printed a second time even though it's on the line before the fork call?
Thanks!
M_MN
You forked your program before flushing stdout (i.e.: data was still in the output buffer). Just call fflush(stdout) to fix it:
❯ cat test.c
#include <stdio.h>
#include <unistd.h>
int main() {
printf("c");
fflush(stdout);
fork();
printf("d");
}
[22:14:01]~/devel
❯ clang test.c -o test
[22:14:07]~/devel
❯ ./test
cdd[22:14:09]~/devel
The reason you're seeing c twice is that the fork() duplicates the unprinted buffered output. You could flush the output stream before the fork():
fflush(stdout);
Or you could set stdout to be unbuffered, but you should do this first, before calling printf() the first time:
setvbuf(stdout, NULL, _IONBF, 0);
Here's what I'm guessing is happening. printf writes to the stream stdout. Since you didn't flush stdout after printing "c" nor did that string end in a new line, the character sat there in a user-space buffer. When you called fork, the child process got a copy of the parent's virtual address space including the buffered text. When both programs exited, their buffers were flushed and so "c" showed up twice.
Try adding fflush(stdout); just prior to the call to fork.

Understanding why fork gives different result in C

Although there are some similar questions like this and this
I still cannot understand why fork gives different output with the following two codes
#include<stdio.h>
void main()
{
printf("Hello World\n");
fork();
}
Gives output
Hello World
Where as this code
#include<stdio.h>
void main()
{
printf("Hello World");
fork();
}
Gives output
Hello WorldHello World
The second case is clear to me from the other questions, that both processes get a copy of the same buffer. So, after the fork, both processes eventually flush the buffer and print the contents to screen separately.
But I am not clear why the first case is so.
Let me explain it in simple words:
Consider,these two statements:
printf("Hello World")
and
printf("Hello World\n")
The STDOUT is line buffered that is printf will be executed only when the buffer is full or when it is terminated by a new line character
printf("Hello World") will not be guaranteed to display the output unless the
Buffer is full or terminated by new line character..Thus when a fork() is called,
Fork will create a copy of a process,this means that after fork, there are two identical processes,
each having a copy of the FILE* STDOUT Therefore, each process will have the same buffer contents of STDOUT
Since in your second program there is no newline character,
each process has the string in its buffer.
Then each process prints another string, and all of the contents are printed since it is terminated by a new line character. This is why you see two identical outputs.
But
In your first program,there is a new line character and it displays output
immediately after the statement is executed and hence it flushes the contents of buffer..thus when a fork() is called
The process tries to access the buffer but since the buffer is empty,it does not print anything
Thus,the different response is due to Buffering behavior of stdout
Hope it helps!!
It's due to the buffering behavior.
#include<stdio.h>
void main()
{
printf("Hello World\n");
fork();
}
flushes the output before you call fork, so the printing is already finished when it was still only a single process.
As to why printf("Hello World\n"); gets flushed immediately and printf("Hello World"); doesn't isn't that easy. It depends on the situation. In your case you probably ran it in the commandline where line buffering is common, line buffering means that it will be flushed once you got a newline. If you write to files it might buffer more before you get any output and you might see 2 outputs in the first case too.
If you want consistent behavior with flushing you might want to do it yourself.

Why is the line following printf(), a call to sleep(), executed before anything is printed?

I thought I was doing something simple here, but C decided to go asynchronous on me. I'm not sure what's going on. Here's my code:
#include <stdio.h>
int main() {
printf("start");
sleep(5);
printf("stop");
}
When I compile and run, I notice that sleep(5) works like a charm. But the compiler decided it was a good idea to skip the first printf() and go out of order, so when running, the program waits for 5 seconds and then prints startstop.
What's the deal? My theory is that the program initiates the print operation with the shell, then continues with the program, leaving Bash to wait until the program is no longer busy to actually render the strings. But I really don't know.
Thanks
printf uses buffered output. This means that data first accumulates in a memory buffer before it is flushed to the output source, which in this case is stdout (which generally defaults to console output). Use fflush after your first printf statement to force it to flush the buffered data to the output source.
#include <stdio.h>
int main() {
printf("start");
fflush(stdout);
sleep(5);
printf("stop");
}
Also see Why does printf not flush after the call unless a newline is in the format string?
Try adding '\n' to your printf statements, like so:
#include <stdio.h>
int main() {
printf("start\n");
sleep(5);
printf("stop\n");
}
The compiler is not executing this out of order. Just the output is getting accumulated, and then displayed when the program exits. The '\n' will invoke the line discipline in the tty drivers to flush the output.
Read this Q&A, it explains it.

Stdin not flushed after normal dummy program

Here is a piece of c code that I wrote after testing some stuffs.
I know this is not a vulnerability concern, but I don't understand why the stdin is not flushed after the normal return of the program, at the point that the prompt get back stdin,stdout,stderr. I mean why the remaining chars on stdin are redirected to stdout after the end of the normal execution of the program and not flushed?
$cat dummy.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int main(){
char rbuf[100];
if (read(0, rbuf,5) == -1){
perror("learn to count");
printf("errno = %d.\n", errno);
exit(1);
}
//printf("rbuf : %s\n",rbuf);
return 1;
}
Here the execution:
$ gcc -o dummy dummy.c
$ ./dummy
AAAAA /bin/sh
$ /bin/sh
sh-3.2$ exit
exit
$
I guess this is just the remaining string of the stdin printed on the mew stdout which is the prompt. Plus the line feed at the end, it somehow emulates the enter pressed by the user to execute a command. What's going on? I'm just curious to know more about that.
Yes, your guess is right, these are extra characters in stdin:
do this:
void flush_stdin()
{
while(getchar() != '\n');
}
Note: do not use fflush() on stdin because that is undefined behavior
edit
The stdin is wired to the terminal which starts the program(which is bash). This starts a new program dummy and the stdin of dummy is wired to the stdin of bash.
From there on, the dummy process reads five characters, neglects the others(leaving them in the stdin buffer). When the control returns to bash it waits until there is atleast one character to read from in the buffer. Low and behold, there are characters in the stdin buffer, hence the program - instead of waiting, starts to read from the stdin and since the stdin at the end, contains \n the process is actually executed. This starts /bin/sh. The rest is up to /bin/sh to worry about!
To execute your program, the shell calls fork(2) to create a child process, and in the child process calls exec(3) to replace itself with the "dummy" program.
I imagine there is something like this in the shell's source code (if it is written in C):
if (fork() == 0)
execlp(program, arguments)
The child process inherits the file descriptors of the parent; in this case the shell. So the child process has the same stdin/stdout as the shell that exec'd it, which is the virtual terminal.
I'm not sure exactly how, but I'd imagine the parent process (the original shell you typed the command in) disregards stdin somehow whilst the child process is running.
When the program exits, the shell gets its stdin back. Any extra characters that weren't read by the your program will go to the shell. And then of course the shell just treats them as a command.
If you try using fgetc(3) instead of read(2) at first it appears the extra characters are lost, not sent to the shell... but, if you unbuffer stdin, you get the same effect using fgetc(2), ie: extra characters go back to the shell.
char rbuf[100];
setbuf(stdin, NULL); // with this line - same effect as using read(2)
// without it - extra characters are lost
for (int i = 0; i < 5; ++i)
rbuf[i] = (char)fgetc(stdin);
By default stdin is line buffered. So it looks like this behaviour is avoided when using buffered stdin because the entire line is read, and extra characters are discarded, whereas unbuffered stdin (or low level reads) will not read until the end of the line, and extra characters remain to be read by the parent (shell) once your program exits.

Resources